summaryrefslogtreecommitdiff
path: root/arch/tile/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/tile/kernel')
-rw-r--r--arch/tile/kernel/backtrace.c81
-rw-r--r--arch/tile/kernel/compat.c28
-rw-r--r--arch/tile/kernel/compat_signal.c10
-rw-r--r--arch/tile/kernel/early_printk.c2
-rw-r--r--arch/tile/kernel/entry.S4
-rw-r--r--arch/tile/kernel/machine_kexec.c38
-rw-r--r--arch/tile/kernel/messaging.c5
-rw-r--r--arch/tile/kernel/module.c16
-rw-r--r--arch/tile/kernel/process.c110
-rw-r--r--arch/tile/kernel/ptrace.c3
-rw-r--r--arch/tile/kernel/reboot.c7
-rw-r--r--arch/tile/kernel/setup.c132
-rw-r--r--arch/tile/kernel/signal.c19
-rw-r--r--arch/tile/kernel/single_step.c75
-rw-r--r--arch/tile/kernel/smpboot.c37
-rw-r--r--arch/tile/kernel/stack.c43
-rw-r--r--arch/tile/kernel/sys.c18
-rw-r--r--arch/tile/kernel/time.c7
-rw-r--r--arch/tile/kernel/traps.c130
-rw-r--r--arch/tile/kernel/vmlinux.lds.S4
20 files changed, 420 insertions, 349 deletions
diff --git a/arch/tile/kernel/backtrace.c b/arch/tile/kernel/backtrace.c
index 1b0a410ef5e..77265f3b58d 100644
--- a/arch/tile/kernel/backtrace.c
+++ b/arch/tile/kernel/backtrace.c
@@ -30,18 +30,18 @@
/** A decoded bundle used for backtracer analysis. */
-typedef struct {
+struct BacktraceBundle {
tile_bundle_bits bits;
int num_insns;
struct tile_decoded_instruction
insns[TILE_MAX_INSTRUCTIONS_PER_BUNDLE];
-} BacktraceBundle;
+};
/* This implementation only makes sense for native tools. */
/** Default function to read memory. */
-static bool
-bt_read_memory(void *result, VirtualAddress addr, size_t size, void *extra)
+static bool bt_read_memory(void *result, VirtualAddress addr,
+ size_t size, void *extra)
{
/* FIXME: this should do some horrible signal stuff to catch
* SEGV cleanly and fail.
@@ -58,11 +58,11 @@ bt_read_memory(void *result, VirtualAddress addr, size_t size, void *extra)
* has the specified mnemonic, and whose first 'num_operands_to_match'
* operands exactly match those in 'operand_values'.
*/
-static const struct tile_decoded_instruction*
-find_matching_insn(const BacktraceBundle *bundle,
- tile_mnemonic mnemonic,
- const int *operand_values,
- int num_operands_to_match)
+static const struct tile_decoded_instruction *find_matching_insn(
+ const struct BacktraceBundle *bundle,
+ tile_mnemonic mnemonic,
+ const int *operand_values,
+ int num_operands_to_match)
{
int i, j;
bool match;
@@ -90,8 +90,7 @@ find_matching_insn(const BacktraceBundle *bundle,
}
/** Does this bundle contain an 'iret' instruction? */
-static inline bool
-bt_has_iret(const BacktraceBundle *bundle)
+static inline bool bt_has_iret(const struct BacktraceBundle *bundle)
{
return find_matching_insn(bundle, TILE_OPC_IRET, NULL, 0) != NULL;
}
@@ -99,8 +98,7 @@ bt_has_iret(const BacktraceBundle *bundle)
/** Does this bundle contain an 'addi sp, sp, OFFSET' or
* 'addli sp, sp, OFFSET' instruction, and if so, what is OFFSET?
*/
-static bool
-bt_has_addi_sp(const BacktraceBundle *bundle, int *adjust)
+static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust)
{
static const int vals[2] = { TREG_SP, TREG_SP };
@@ -120,8 +118,7 @@ bt_has_addi_sp(const BacktraceBundle *bundle, int *adjust)
* as an unsigned value by this code since that's what the caller wants.
* Returns the number of info ops found.
*/
-static int
-bt_get_info_ops(const BacktraceBundle *bundle,
+static int bt_get_info_ops(const struct BacktraceBundle *bundle,
int operands[MAX_INFO_OPS_PER_BUNDLE])
{
int num_ops = 0;
@@ -143,8 +140,7 @@ bt_get_info_ops(const BacktraceBundle *bundle,
/** Does this bundle contain a jrp instruction, and if so, to which
* register is it jumping?
*/
-static bool
-bt_has_jrp(const BacktraceBundle *bundle, int *target_reg)
+static bool bt_has_jrp(const struct BacktraceBundle *bundle, int *target_reg)
{
const struct tile_decoded_instruction *insn =
find_matching_insn(bundle, TILE_OPC_JRP, NULL, 0);
@@ -156,8 +152,7 @@ bt_has_jrp(const BacktraceBundle *bundle, int *target_reg)
}
/** Does this bundle modify the specified register in any way? */
-static bool
-bt_modifies_reg(const BacktraceBundle *bundle, int reg)
+static bool bt_modifies_reg(const struct BacktraceBundle *bundle, int reg)
{
int i, j;
for (i = 0; i < bundle->num_insns; i++) {
@@ -177,30 +172,26 @@ bt_modifies_reg(const BacktraceBundle *bundle, int reg)
}
/** Does this bundle modify sp? */
-static inline bool
-bt_modifies_sp(const BacktraceBundle *bundle)
+static inline bool bt_modifies_sp(const struct BacktraceBundle *bundle)
{
return bt_modifies_reg(bundle, TREG_SP);
}
/** Does this bundle modify lr? */
-static inline bool
-bt_modifies_lr(const BacktraceBundle *bundle)
+static inline bool bt_modifies_lr(const struct BacktraceBundle *bundle)
{
return bt_modifies_reg(bundle, TREG_LR);
}
/** Does this bundle contain the instruction 'move fp, sp'? */
-static inline bool
-bt_has_move_r52_sp(const BacktraceBundle *bundle)
+static inline bool bt_has_move_r52_sp(const struct BacktraceBundle *bundle)
{
static const int vals[2] = { 52, TREG_SP };
return find_matching_insn(bundle, TILE_OPC_MOVE, vals, 2) != NULL;
}
/** Does this bundle contain the instruction 'sw sp, lr'? */
-static inline bool
-bt_has_sw_sp_lr(const BacktraceBundle *bundle)
+static inline bool bt_has_sw_sp_lr(const struct BacktraceBundle *bundle)
{
static const int vals[2] = { TREG_SP, TREG_LR };
return find_matching_insn(bundle, TILE_OPC_SW, vals, 2) != NULL;
@@ -209,11 +200,10 @@ bt_has_sw_sp_lr(const BacktraceBundle *bundle)
/** Locates the caller's PC and SP for a program starting at the
* given address.
*/
-static void
-find_caller_pc_and_caller_sp(CallerLocation *location,
- const VirtualAddress start_pc,
- BacktraceMemoryReader read_memory_func,
- void *read_memory_func_extra)
+static void find_caller_pc_and_caller_sp(CallerLocation *location,
+ const VirtualAddress start_pc,
+ BacktraceMemoryReader read_memory_func,
+ void *read_memory_func_extra)
{
/* Have we explicitly decided what the sp is,
* rather than just the default?
@@ -253,7 +243,7 @@ find_caller_pc_and_caller_sp(CallerLocation *location,
for (pc = start_pc;; pc += sizeof(tile_bundle_bits)) {
- BacktraceBundle bundle;
+ struct BacktraceBundle bundle;
int num_info_ops, info_operands[MAX_INFO_OPS_PER_BUNDLE];
int one_ago, jrp_reg;
bool has_jrp;
@@ -475,12 +465,11 @@ find_caller_pc_and_caller_sp(CallerLocation *location,
}
}
-void
-backtrace_init(BacktraceIterator *state,
- BacktraceMemoryReader read_memory_func,
- void *read_memory_func_extra,
- VirtualAddress pc, VirtualAddress lr,
- VirtualAddress sp, VirtualAddress r52)
+void backtrace_init(BacktraceIterator *state,
+ BacktraceMemoryReader read_memory_func,
+ void *read_memory_func_extra,
+ VirtualAddress pc, VirtualAddress lr,
+ VirtualAddress sp, VirtualAddress r52)
{
CallerLocation location;
VirtualAddress fp, initial_frame_caller_pc;
@@ -558,8 +547,7 @@ backtrace_init(BacktraceIterator *state,
state->read_memory_func_extra = read_memory_func_extra;
}
-bool
-backtrace_next(BacktraceIterator *state)
+bool backtrace_next(BacktraceIterator *state)
{
VirtualAddress next_fp, next_pc, next_frame[2];
@@ -614,12 +602,11 @@ backtrace_next(BacktraceIterator *state)
#else /* TILE_CHIP < 10 */
-void
-backtrace_init(BacktraceIterator *state,
- BacktraceMemoryReader read_memory_func,
- void *read_memory_func_extra,
- VirtualAddress pc, VirtualAddress lr,
- VirtualAddress sp, VirtualAddress r52)
+void backtrace_init(BacktraceIterator *state,
+ BacktraceMemoryReader read_memory_func,
+ void *read_memory_func_extra,
+ VirtualAddress pc, VirtualAddress lr,
+ VirtualAddress sp, VirtualAddress r52)
{
state->pc = pc;
state->sp = sp;
diff --git a/arch/tile/kernel/compat.c b/arch/tile/kernel/compat.c
index a374c99deeb..b1e06d04155 100644
--- a/arch/tile/kernel/compat.c
+++ b/arch/tile/kernel/compat.c
@@ -88,34 +88,14 @@ long compat_sys_sched_rr_get_interval(compat_pid_t pid,
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
- ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t);
+ ret = sys_sched_rr_get_interval(pid,
+ (struct timespec __force __user *)&t);
set_fs(old_fs);
if (put_compat_timespec(&t, interval))
return -EFAULT;
return ret;
}
-ssize_t compat_sys_sendfile(int out_fd, int in_fd, compat_off_t __user *offset,
- size_t count)
-{
- mm_segment_t old_fs = get_fs();
- int ret;
- off_t of;
-
- if (offset && get_user(of, offset))
- return -EFAULT;
-
- set_fs(KERNEL_DS);
- ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL,
- count);
- set_fs(old_fs);
-
- if (offset && put_user(of, offset))
- return -EFAULT;
- return ret;
-}
-
-
/*
* The usual compat_sys_msgsnd() and _msgrcv() seem to be assuming
* some different calling convention than our normal 32-bit tile code.
@@ -177,6 +157,10 @@ long tile_compat_sys_msgrcv(int msqid,
/* Pass full 64-bit values through ptrace. */
#define compat_sys_ptrace tile_compat_sys_ptrace
+/*
+ * Note that we can't include <linux/unistd.h> here since the header
+ * guard will defeat us; <asm/unistd.h> checks for __SYSCALL as well.
+ */
void *compat_sys_call_table[__NR_syscalls] = {
[0 ... __NR_syscalls-1] = sys_ni_syscall,
#include <asm/unistd.h>
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c
index 9fa4ba8ed5f..d5efb215dd5 100644
--- a/arch/tile/kernel/compat_signal.c
+++ b/arch/tile/kernel/compat_signal.c
@@ -32,13 +32,14 @@
#include <asm/processor.h>
#include <asm/ucontext.h>
#include <asm/sigframe.h>
+#include <asm/syscalls.h>
#include <arch/interrupts.h>
struct compat_sigaction {
compat_uptr_t sa_handler;
compat_ulong_t sa_flags;
compat_uptr_t sa_restorer;
- sigset_t sa_mask; /* mask last for extensibility */
+ sigset_t sa_mask __packed;
};
struct compat_sigaltstack {
@@ -170,7 +171,7 @@ long compat_sys_rt_sigqueueinfo(int pid, int sig,
if (copy_siginfo_from_user32(&info, uinfo))
return -EFAULT;
set_fs(KERNEL_DS);
- ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
+ ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __force __user *)&info);
set_fs(old_fs);
return ret;
}
@@ -274,7 +275,8 @@ long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
}
seg = get_fs();
set_fs(KERNEL_DS);
- ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss,
+ ret = do_sigaltstack(uss_ptr ? (stack_t __user __force *)&uss : NULL,
+ (stack_t __user __force *)&uoss,
(unsigned long)compat_ptr(regs->sp));
set_fs(seg);
if (ret >= 0 && uoss_ptr) {
@@ -336,7 +338,7 @@ static inline void __user *compat_get_sigframe(struct k_sigaction *ka,
* will die with SIGSEGV.
*/
if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size)))
- return (void __user *) -1L;
+ return (void __user __force *)-1UL;
/* This is the X/Open sanctioned signal stack switching. */
if (ka->sa.sa_flags & SA_ONSTACK) {
diff --git a/arch/tile/kernel/early_printk.c b/arch/tile/kernel/early_printk.c
index e44d441e3f3..2c54fd43a8a 100644
--- a/arch/tile/kernel/early_printk.c
+++ b/arch/tile/kernel/early_printk.c
@@ -32,7 +32,7 @@ static struct console early_hv_console = {
};
/* Direct interface for emergencies */
-struct console *early_console = &early_hv_console;
+static struct console *early_console = &early_hv_console;
static int early_console_initialized;
static int early_console_complete;
diff --git a/arch/tile/kernel/entry.S b/arch/tile/kernel/entry.S
index 136261f7d7f..3d01383b1b0 100644
--- a/arch/tile/kernel/entry.S
+++ b/arch/tile/kernel/entry.S
@@ -13,9 +13,9 @@
*/
#include <linux/linkage.h>
-#include <arch/abi.h>
-#include <asm/unistd.h>
+#include <linux/unistd.h>
#include <asm/irqflags.h>
+#include <arch/abi.h>
#ifdef __tilegx__
#define bnzt bnezt
diff --git a/arch/tile/kernel/machine_kexec.c b/arch/tile/kernel/machine_kexec.c
index ed3e1cb8dcc..ba7a265d617 100644
--- a/arch/tile/kernel/machine_kexec.c
+++ b/arch/tile/kernel/machine_kexec.c
@@ -75,13 +75,13 @@ void machine_crash_shutdown(struct pt_regs *regs)
int machine_kexec_prepare(struct kimage *image)
{
if (num_online_cpus() > 1) {
- printk(KERN_WARNING "%s: detected attempt to kexec "
+ pr_warning("%s: detected attempt to kexec "
"with num_online_cpus() > 1\n",
__func__);
return -ENOSYS;
}
if (image->type != KEXEC_TYPE_DEFAULT) {
- printk(KERN_WARNING "%s: detected attempt to kexec "
+ pr_warning("%s: detected attempt to kexec "
"with unsupported type: %d\n",
__func__,
image->type);
@@ -124,22 +124,13 @@ static unsigned char *kexec_bn2cl(void *pg)
return 0;
/*
- * If we get a checksum mismatch, it's possible that this is
- * just a false positive, but relatively unlikely. We dump
- * out the contents of the section so we can diagnose better.
+ * If we get a checksum mismatch, warn with the checksum
+ * so we can diagnose better.
*/
csum = ip_compute_csum(pg, bhdrp->b_size);
if (csum != 0) {
- int i;
- unsigned char *p = pg;
- int nbytes = min((Elf32_Word)1000, bhdrp->b_size);
- printk(KERN_INFO "%s: bad checksum %#x\n", __func__, csum);
- printk(KERN_INFO "bytes (%d):", bhdrp->b_size);
- for (i = 0; i < nbytes; ++i)
- printk(" %02x", p[i]);
- if (bhdrp->b_size != nbytes)
- printk(" ...");
- printk("\n");
+ pr_warning("%s: bad checksum %#x (size %d)\n",
+ __func__, csum, bhdrp->b_size);
return 0;
}
@@ -156,7 +147,7 @@ static unsigned char *kexec_bn2cl(void *pg)
if ((unsigned char *) (nhdrp + 1) >
((unsigned char *) pg) + bhdrp->b_size) {
- printk(KERN_INFO "%s: out of bounds\n", __func__);
+ pr_info("%s: out of bounds\n", __func__);
return 0;
}
}
@@ -167,7 +158,7 @@ static unsigned char *kexec_bn2cl(void *pg)
while (*desc != '\0') {
desc++;
if (((unsigned long)desc & PAGE_MASK) != (unsigned long)pg) {
- printk(KERN_INFO "%s: ran off end of page\n",
+ pr_info("%s: ran off end of page\n",
__func__);
return 0;
}
@@ -202,23 +193,20 @@ static void kexec_find_and_set_command_line(struct kimage *image)
}
if (command_line != 0) {
- printk(KERN_INFO "setting new command line to \"%s\"\n",
+ pr_info("setting new command line to \"%s\"\n",
command_line);
hverr = hv_set_command_line(
(HV_VirtAddr) command_line, strlen(command_line));
kunmap_atomic(command_line, KM_USER0);
} else {
- printk(KERN_INFO "%s: no command line found; making empty\n",
+ pr_info("%s: no command line found; making empty\n",
__func__);
hverr = hv_set_command_line((HV_VirtAddr) command_line, 0);
}
- if (hverr) {
- printk(KERN_WARNING
- "%s: call to hv_set_command_line returned error: %d\n",
- __func__, hverr);
-
- }
+ if (hverr)
+ pr_warning("%s: hv_set_command_line returned error: %d\n",
+ __func__, hverr);
}
/*
diff --git a/arch/tile/kernel/messaging.c b/arch/tile/kernel/messaging.c
index f991f5285d8..6d23ed271d1 100644
--- a/arch/tile/kernel/messaging.c
+++ b/arch/tile/kernel/messaging.c
@@ -18,13 +18,14 @@
#include <linux/ptrace.h>
#include <asm/hv_driver.h>
#include <asm/irq_regs.h>
+#include <asm/traps.h>
#include <hv/hypervisor.h>
#include <arch/interrupts.h>
/* All messages are stored here */
static DEFINE_PER_CPU(HV_MsgState, msg_state);
-void __cpuinit init_messaging()
+void __cpuinit init_messaging(void)
{
/* Allocate storage for messages in kernel space */
HV_MsgState *state = &__get_cpu_var(msg_state);
@@ -58,7 +59,7 @@ void hv_message_intr(struct pt_regs *regs, int intnum)
{
long sp = stack_pointer - (long) current_thread_info();
if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) {
- printk(KERN_EMERG "hv_message_intr: "
+ pr_emerg("hv_message_intr: "
"stack overflow: %ld\n",
sp - sizeof(struct thread_info));
dump_stack();
diff --git a/arch/tile/kernel/module.c b/arch/tile/kernel/module.c
index ed3e91161f8..e2ab82b7c7e 100644
--- a/arch/tile/kernel/module.c
+++ b/arch/tile/kernel/module.c
@@ -107,7 +107,7 @@ int apply_relocate(Elf_Shdr *sechdrs,
unsigned int relsec,
struct module *me)
{
- printk(KERN_ERR "module %s: .rel relocation unsupported\n", me->name);
+ pr_err("module %s: .rel relocation unsupported\n", me->name);
return -ENOEXEC;
}
@@ -119,8 +119,8 @@ int apply_relocate(Elf_Shdr *sechdrs,
static int validate_hw2_last(long value, struct module *me)
{
if (((value << 16) >> 16) != value) {
- printk("module %s: Out of range HW2_LAST value %#lx\n",
- me->name, value);
+ pr_warning("module %s: Out of range HW2_LAST value %#lx\n",
+ me->name, value);
return 0;
}
return 1;
@@ -223,10 +223,10 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
value -= (unsigned long) location; /* pc-relative */
value = (long) value >> 3; /* count by instrs */
if (!validate_jumpoff(value)) {
- printk("module %s: Out of range jump to"
- " %#llx at %#llx (%p)\n", me->name,
- sym->st_value + rel[i].r_addend,
- rel[i].r_offset, location);
+ pr_warning("module %s: Out of range jump to"
+ " %#llx at %#llx (%p)\n", me->name,
+ sym->st_value + rel[i].r_addend,
+ rel[i].r_offset, location);
return -ENOEXEC;
}
MUNGE(create_JumpOff_X1);
@@ -236,7 +236,7 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
#undef MUNGE
default:
- printk(KERN_ERR "module %s: Unknown relocation: %d\n",
+ pr_err("module %s: Unknown relocation: %d\n",
me->name, (int) ELF_R_TYPE(rel[i].r_info));
return -ENOEXEC;
}
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index c70ff14a48e..ed590ad0acd 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -24,9 +24,14 @@
#include <linux/compat.h>
#include <linux/hardirq.h>
#include <linux/syscalls.h>
+#include <linux/kernel.h>
#include <asm/system.h>
#include <asm/stack.h>
#include <asm/homecache.h>
+#include <asm/syscalls.h>
+#ifdef CONFIG_HARDWALL
+#include <asm/hardwall.h>
+#endif
#include <arch/chip.h>
#include <arch/abi.h>
@@ -43,7 +48,7 @@ static int __init idle_setup(char *str)
return -EINVAL;
if (!strcmp(str, "poll")) {
- printk("using polling idle threads.\n");
+ pr_info("using polling idle threads.\n");
no_idle_nap = 1;
} else if (!strcmp(str, "halt"))
no_idle_nap = 0;
@@ -62,7 +67,6 @@ early_param("idle", idle_setup);
*/
void cpu_idle(void)
{
- extern void _cpu_idle(void);
int cpu = smp_processor_id();
@@ -108,7 +112,7 @@ void cpu_idle(void)
struct thread_info *alloc_thread_info(struct task_struct *task)
{
struct page *page;
- int flags = GFP_KERNEL;
+ gfp_t flags = GFP_KERNEL;
#ifdef CONFIG_DEBUG_STACK_USAGE
flags |= __GFP_ZERO;
@@ -116,7 +120,7 @@ struct thread_info *alloc_thread_info(struct task_struct *task)
page = alloc_pages(flags, THREAD_SIZE_ORDER);
if (!page)
- return 0;
+ return NULL;
return (struct thread_info *)page_address(page);
}
@@ -129,6 +133,18 @@ void free_thread_info(struct thread_info *info)
{
struct single_step_state *step_state = info->step_state;
+#ifdef CONFIG_HARDWALL
+ /*
+ * We free a thread_info from the context of the task that has
+ * been scheduled next, so the original task is already dead.
+ * Calling deactivate here just frees up the data structures.
+ * If the task we're freeing held the last reference to a
+ * hardwall fd, it would have been released prior to this point
+ * anyway via exit_files(), and "hardwall" would be NULL by now.
+ */
+ if (info->task->thread.hardwall)
+ hardwall_deactivate(info->task);
+#endif
if (step_state) {
@@ -154,8 +170,6 @@ void free_thread_info(struct thread_info *info)
static void save_arch_state(struct thread_struct *t);
-extern void ret_from_fork(void);
-
int copy_thread(unsigned long clone_flags, unsigned long sp,
unsigned long stack_size,
struct task_struct *p, struct pt_regs *regs)
@@ -235,6 +249,10 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
p->thread.proc_status = 0;
#endif
+#ifdef CONFIG_HARDWALL
+ /* New thread does not own any networks. */
+ p->thread.hardwall = NULL;
+#endif
/*
@@ -257,7 +275,7 @@ struct task_struct *validate_current(void)
if (unlikely((unsigned long)tsk < PAGE_OFFSET ||
(void *)tsk > high_memory ||
((unsigned long)tsk & (__alignof__(*tsk) - 1)) != 0)) {
- printk("Corrupt 'current' %p (sp %#lx)\n", tsk, stack_pointer);
+ pr_err("Corrupt 'current' %p (sp %#lx)\n", tsk, stack_pointer);
tsk = &corrupt;
}
return tsk;
@@ -447,10 +465,6 @@ void _prepare_arch_switch(struct task_struct *next)
}
-extern struct task_struct *__switch_to(struct task_struct *prev,
- struct task_struct *next,
- unsigned long new_system_save_1_0);
-
struct task_struct *__sched _switch_to(struct task_struct *prev,
struct task_struct *next)
{
@@ -486,6 +500,15 @@ struct task_struct *__sched _switch_to(struct task_struct *prev,
}
#endif
+#ifdef CONFIG_HARDWALL
+ /* Enable or disable access to the network registers appropriately. */
+ if (prev->thread.hardwall != NULL) {
+ if (next->thread.hardwall == NULL)
+ restrict_network_mpls();
+ } else if (next->thread.hardwall != NULL) {
+ grant_network_mpls();
+ }
+#endif
/*
* Switch kernel SP, PC, and callee-saved registers.
@@ -496,14 +519,14 @@ struct task_struct *__sched _switch_to(struct task_struct *prev,
return __switch_to(prev, next, next_current_ksp0(next));
}
-int _sys_fork(struct pt_regs *regs)
+long _sys_fork(struct pt_regs *regs)
{
return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);
}
-int _sys_clone(unsigned long clone_flags, unsigned long newsp,
- void __user *parent_tidptr, void __user *child_tidptr,
- struct pt_regs *regs)
+long _sys_clone(unsigned long clone_flags, unsigned long newsp,
+ void __user *parent_tidptr, void __user *child_tidptr,
+ struct pt_regs *regs)
{
if (!newsp)
newsp = regs->sp;
@@ -511,7 +534,7 @@ int _sys_clone(unsigned long clone_flags, unsigned long newsp,
parent_tidptr, child_tidptr);
}
-int _sys_vfork(struct pt_regs *regs)
+long _sys_vfork(struct pt_regs *regs)
{
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp,
regs, 0, NULL, NULL);
@@ -520,10 +543,10 @@ int _sys_vfork(struct pt_regs *regs)
/*
* sys_execve() executes a new program.
*/
-int _sys_execve(char __user *path, char __user *__user *argv,
- char __user *__user *envp, struct pt_regs *regs)
+long _sys_execve(char __user *path, char __user *__user *argv,
+ char __user *__user *envp, struct pt_regs *regs)
{
- int error;
+ long error;
char *filename;
filename = getname(path);
@@ -537,10 +560,10 @@ out:
}
#ifdef CONFIG_COMPAT
-int _compat_sys_execve(char __user *path, compat_uptr_t __user *argv,
- compat_uptr_t __user *envp, struct pt_regs *regs)
+long _compat_sys_execve(char __user *path, compat_uptr_t __user *argv,
+ compat_uptr_t __user *envp, struct pt_regs *regs)
{
- int error;
+ long error;
char *filename;
filename = getname(path);
@@ -616,31 +639,32 @@ void exit_thread(void)
/* Nothing */
}
-#ifdef __tilegx__
-# define LINECOUNT 3
-# define EXTRA_NL "\n"
-#else
-# define LINECOUNT 4
-# define EXTRA_NL ""
-#endif
-
void show_regs(struct pt_regs *regs)
{
struct task_struct *tsk = validate_current();
- int i, linebreak;
- printk("\n");
- printk(" Pid: %d, comm: %20s, CPU: %d\n",
+ int i;
+
+ pr_err("\n");
+ pr_err(" Pid: %d, comm: %20s, CPU: %d\n",
tsk->pid, tsk->comm, smp_processor_id());
- for (i = linebreak = 0; i < 53; ++i) {
- printk(" r%-2d: "REGFMT, i, regs->regs[i]);
- if (++linebreak == LINECOUNT) {
- linebreak = 0;
- printk("\n");
- }
- }
- printk(" tp : "REGFMT EXTRA_NL " sp : "REGFMT" lr : "REGFMT"\n",
- regs->tp, regs->sp, regs->lr);
- printk(" pc : "REGFMT" ex1: %ld faultnum: %ld\n",
+#ifdef __tilegx__
+ for (i = 0; i < 51; i += 3)
+ pr_err(" r%-2d: "REGFMT" r%-2d: "REGFMT" r%-2d: "REGFMT"\n",
+ i, regs->regs[i], i+1, regs->regs[i+1],
+ i+2, regs->regs[i+2]);
+ pr_err(" r51: "REGFMT" r52: "REGFMT" tp : "REGFMT"\n",
+ regs->regs[51], regs->regs[52], regs->tp);
+ pr_err(" sp : "REGFMT" lr : "REGFMT"\n", regs->sp, regs->lr);
+#else
+ for (i = 0; i < 52; i += 3)
+ pr_err(" r%-2d: "REGFMT" r%-2d: "REGFMT
+ " r%-2d: "REGFMT" r%-2d: "REGFMT"\n",
+ i, regs->regs[i], i+1, regs->regs[i+1],
+ i+2, regs->regs[i+2], i+3, regs->regs[i+3]);
+ pr_err(" r52: "REGFMT" tp : "REGFMT" sp : "REGFMT" lr : "REGFMT"\n",
+ regs->regs[52], regs->tp, regs->sp, regs->lr);
+#endif
+ pr_err(" pc : "REGFMT" ex1: %ld faultnum: %ld\n",
regs->pc, regs->ex1, regs->faultnum);
dump_stack_regs(regs);
diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c
index 468054928e7..e5701d1a52d 100644
--- a/arch/tile/kernel/ptrace.c
+++ b/arch/tile/kernel/ptrace.c
@@ -19,6 +19,7 @@
#include <linux/kprobes.h>
#include <linux/compat.h>
#include <linux/uaccess.h>
+#include <asm/traps.h>
void user_enable_single_step(struct task_struct *child)
{
@@ -76,7 +77,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
if (task_thread_info(child)->status & TS_COMPAT)
addr = (u32)addr;
#endif
- datap = (unsigned long __user *)data;
+ datap = (unsigned long __user __force *)data;
switch (request) {
diff --git a/arch/tile/kernel/reboot.c b/arch/tile/kernel/reboot.c
index a4523923605..acd86d20beb 100644
--- a/arch/tile/kernel/reboot.c
+++ b/arch/tile/kernel/reboot.c
@@ -15,6 +15,7 @@
#include <linux/stddef.h>
#include <linux/reboot.h>
#include <linux/smp.h>
+#include <linux/pm.h>
#include <asm/page.h>
#include <asm/setup.h>
#include <hv/hypervisor.h>
@@ -46,7 +47,5 @@ void machine_restart(char *cmd)
hv_restart((HV_VirtAddr) "vmlinux", (HV_VirtAddr) cmd);
}
-/*
- * Power off function, if any
- */
-void (*pm_power_off)(void) = machine_power_off;
+/* No interesting distinction to be made here. */
+void (*pm_power_off)(void) = NULL;
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c
index 934136b61ce..4dd21c1e6d5 100644
--- a/arch/tile/kernel/setup.c
+++ b/arch/tile/kernel/setup.c
@@ -20,6 +20,7 @@
#include <linux/node.h>
#include <linux/cpu.h>
#include <linux/ioport.h>
+#include <linux/irq.h>
#include <linux/kexec.h>
#include <linux/pci.h>
#include <linux/initrd.h>
@@ -109,7 +110,7 @@ static int __init setup_maxmem(char *str)
maxmem_pfn = (maxmem_mb >> (HPAGE_SHIFT - 20)) <<
(HPAGE_SHIFT - PAGE_SHIFT);
- printk("Forcing RAM used to no more than %dMB\n",
+ pr_info("Forcing RAM used to no more than %dMB\n",
maxmem_pfn >> (20 - PAGE_SHIFT));
return 0;
}
@@ -127,7 +128,7 @@ static int __init setup_maxnodemem(char *str)
maxnodemem_pfn[node] = (maxnodemem_mb >> (HPAGE_SHIFT - 20)) <<
(HPAGE_SHIFT - PAGE_SHIFT);
- printk("Forcing RAM used on node %ld to no more than %dMB\n",
+ pr_info("Forcing RAM used on node %ld to no more than %dMB\n",
node, maxnodemem_pfn[node] >> (20 - PAGE_SHIFT));
return 0;
}
@@ -140,7 +141,7 @@ static int __init setup_isolnodes(char *str)
return -EINVAL;
nodelist_scnprintf(buf, sizeof(buf), isolnodes);
- printk("Set isolnodes value to '%s'\n", buf);
+ pr_info("Set isolnodes value to '%s'\n", buf);
return 0;
}
early_param("isolnodes", setup_isolnodes);
@@ -155,7 +156,7 @@ static int __init setup_pci_reserve(char* str)
return -EINVAL;
pci_reserve_mb = mb;
- printk("Reserving %dMB for PCIE root complex mappings\n",
+ pr_info("Reserving %dMB for PCIE root complex mappings\n",
pci_reserve_mb);
return 0;
}
@@ -269,7 +270,7 @@ static void *__init setup_pa_va_mapping(void)
* This is up to 4 mappings for lowmem, one mapping per memory
* controller, plus one for our text segment.
*/
-void __cpuinit store_permanent_mappings(void)
+static void __cpuinit store_permanent_mappings(void)
{
int i;
@@ -320,14 +321,14 @@ static void __init setup_memory(void)
break;
#ifdef CONFIG_FLATMEM
if (i > 0) {
- printk("Can't use discontiguous PAs: %#llx..%#llx\n",
+ pr_err("Can't use discontiguous PAs: %#llx..%#llx\n",
range.size, range.start + range.size);
continue;
}
#endif
#ifndef __tilegx__
if ((unsigned long)range.start) {
- printk("Range not at 4GB multiple: %#llx..%#llx\n",
+ pr_err("Range not at 4GB multiple: %#llx..%#llx\n",
range.start, range.start + range.size);
continue;
}
@@ -335,51 +336,51 @@ static void __init setup_memory(void)
if ((range.start & (HPAGE_SIZE-1)) != 0 ||
(range.size & (HPAGE_SIZE-1)) != 0) {
unsigned long long start_pa = range.start;
- unsigned long long size = range.size;
+ unsigned long long orig_size = range.size;
range.start = (start_pa + HPAGE_SIZE - 1) & HPAGE_MASK;
range.size -= (range.start - start_pa);
range.size &= HPAGE_MASK;
- printk("Range not hugepage-aligned: %#llx..%#llx:"
+ pr_err("Range not hugepage-aligned: %#llx..%#llx:"
" now %#llx-%#llx\n",
- start_pa, start_pa + size,
+ start_pa, start_pa + orig_size,
range.start, range.start + range.size);
}
highbits = __pa_to_highbits(range.start);
if (highbits >= NR_PA_HIGHBIT_VALUES) {
- printk("PA high bits too high: %#llx..%#llx\n",
+ pr_err("PA high bits too high: %#llx..%#llx\n",
range.start, range.start + range.size);
continue;
}
if (highbits_seen[highbits]) {
- printk("Range overlaps in high bits: %#llx..%#llx\n",
+ pr_err("Range overlaps in high bits: %#llx..%#llx\n",
range.start, range.start + range.size);
continue;
}
highbits_seen[highbits] = 1;
if (PFN_DOWN(range.size) > maxnodemem_pfn[i]) {
- int size = maxnodemem_pfn[i];
- if (size > 0) {
- printk("Maxnodemem reduced node %d to"
- " %d pages\n", i, size);
- range.size = (HV_PhysAddr)size << PAGE_SHIFT;
+ int max_size = maxnodemem_pfn[i];
+ if (max_size > 0) {
+ pr_err("Maxnodemem reduced node %d to"
+ " %d pages\n", i, max_size);
+ range.size = PFN_PHYS(max_size);
} else {
- printk("Maxnodemem disabled node %d\n", i);
+ pr_err("Maxnodemem disabled node %d\n", i);
continue;
}
}
if (num_physpages + PFN_DOWN(range.size) > maxmem_pfn) {
- int size = maxmem_pfn - num_physpages;
- if (size > 0) {
- printk("Maxmem reduced node %d to %d pages\n",
- i, size);
- range.size = (HV_PhysAddr)size << PAGE_SHIFT;
+ int max_size = maxmem_pfn - num_physpages;
+ if (max_size > 0) {
+ pr_err("Maxmem reduced node %d to %d pages\n",
+ i, max_size);
+ range.size = PFN_PHYS(max_size);
} else {
- printk("Maxmem disabled node %d\n", i);
+ pr_err("Maxmem disabled node %d\n", i);
continue;
}
}
if (i >= MAX_NUMNODES) {
- printk("Too many PA nodes (#%d): %#llx...%#llx\n",
+ pr_err("Too many PA nodes (#%d): %#llx...%#llx\n",
i, range.size, range.size + range.start);
continue;
}
@@ -391,7 +392,7 @@ static void __init setup_memory(void)
#ifndef __tilegx__
if (((HV_PhysAddr)end << PAGE_SHIFT) !=
(range.start + range.size)) {
- printk("PAs too high to represent: %#llx..%#llx\n",
+ pr_err("PAs too high to represent: %#llx..%#llx\n",
range.start, range.start + range.size);
continue;
}
@@ -412,7 +413,7 @@ static void __init setup_memory(void)
NR_CPUS * (PFN_UP(per_cpu_size) >> PAGE_SHIFT);
if (end < pci_reserve_end_pfn + percpu_pages) {
end = pci_reserve_start_pfn;
- printk("PCI mapping region reduced node %d to"
+ pr_err("PCI mapping region reduced node %d to"
" %ld pages\n", i, end - start);
}
}
@@ -456,11 +457,11 @@ static void __init setup_memory(void)
}
}
num_physpages -= dropped_pages;
- printk(KERN_WARNING "Only using %ldMB memory;"
+ pr_warning("Only using %ldMB memory;"
" ignoring %ldMB.\n",
num_physpages >> (20 - PAGE_SHIFT),
dropped_pages >> (20 - PAGE_SHIFT));
- printk(KERN_WARNING "Consider using a larger page size.\n");
+ pr_warning("Consider using a larger page size.\n");
}
#endif
@@ -478,9 +479,9 @@ static void __init setup_memory(void)
MAXMEM_PFN : mappable_physpages;
highmem_pages = (long) (num_physpages - lowmem_pages);
- printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
+ pr_notice("%ldMB HIGHMEM available.\n",
pages_to_mb(highmem_pages > 0 ? highmem_pages : 0));
- printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
+ pr_notice("%ldMB LOWMEM available.\n",
pages_to_mb(lowmem_pages));
#else
/* Set max_low_pfn based on what node 0 can directly address. */
@@ -488,15 +489,15 @@ static void __init setup_memory(void)
#ifndef __tilegx__
if (node_end_pfn[0] > MAXMEM_PFN) {
- printk(KERN_WARNING "Only using %ldMB LOWMEM.\n",
+ pr_warning("Only using %ldMB LOWMEM.\n",
MAXMEM>>20);
- printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
+ pr_warning("Use a HIGHMEM enabled kernel.\n");
max_low_pfn = MAXMEM_PFN;
max_pfn = MAXMEM_PFN;
num_physpages = MAXMEM_PFN;
node_end_pfn[0] = MAXMEM_PFN;
} else {
- printk(KERN_NOTICE "%ldMB memory available.\n",
+ pr_notice("%ldMB memory available.\n",
pages_to_mb(node_end_pfn[0]));
}
for (i = 1; i < MAX_NUMNODES; ++i) {
@@ -512,7 +513,7 @@ static void __init setup_memory(void)
if (pages)
high_memory = pfn_to_kaddr(node_end_pfn[i]);
}
- printk(KERN_NOTICE "%ldMB memory available.\n",
+ pr_notice("%ldMB memory available.\n",
pages_to_mb(lowmem_pages));
#endif
#endif
@@ -744,7 +745,7 @@ static void __init setup_numa_mapping(void)
nodes_andnot(default_nodes, node_online_map, isolnodes);
if (nodes_empty(default_nodes)) {
BUG_ON(!node_isset(0, node_online_map));
- printk("Forcing NUMA node zero available as a default node\n");
+ pr_err("Forcing NUMA node zero available as a default node\n");
node_set(0, default_nodes);
}
@@ -822,13 +823,13 @@ static void __init setup_numa_mapping(void)
printk(KERN_DEBUG "NUMA cpu-to-node row %d:", y);
for (x = 0; x < smp_width; ++x, ++cpu) {
if (cpu_to_node(cpu) < 0) {
- printk(" -");
+ pr_cont(" -");
cpu_2_node[cpu] = first_node(default_nodes);
} else {
- printk(" %d", cpu_to_node(cpu));
+ pr_cont(" %d", cpu_to_node(cpu));
}
}
- printk("\n");
+ pr_cont("\n");
}
}
@@ -856,12 +857,17 @@ subsys_initcall(topology_init);
#endif /* CONFIG_NUMA */
/**
- * setup_mpls() - Allow the user-space code to access various SPRs.
+ * setup_cpu() - Do all necessary per-cpu, tile-specific initialization.
+ * @boot: Is this the boot cpu?
*
- * Also called from online_secondary().
+ * Called from setup_arch() on the boot cpu, or online_secondary().
*/
-void __cpuinit setup_mpls(void)
+void __cpuinit setup_cpu(int boot)
{
+ /* The boot cpu sets up its permanent mappings much earlier. */
+ if (!boot)
+ store_permanent_mappings();
+
/* Allow asynchronous TLB interrupts. */
#if CHIP_HAS_TILE_DMA()
raw_local_irq_unmask(INT_DMATLB_MISS);
@@ -892,6 +898,14 @@ void __cpuinit setup_mpls(void)
* as well as the PL 0 interrupt mask.
*/
__insn_mtspr(SPR_MPL_INTCTRL_0_SET_0, 1);
+
+ /* Initialize IRQ support for this cpu. */
+ setup_irq_regs();
+
+#ifdef CONFIG_HARDWALL
+ /* Reset the network state on this cpu. */
+ reset_network_state();
+#endif
}
static int __initdata set_initramfs_file;
@@ -922,22 +936,22 @@ static void __init load_hv_initrd(void)
fd = hv_fs_findfile((HV_VirtAddr) initramfs_file);
if (fd == HV_ENOENT) {
if (set_initramfs_file)
- printk("No such hvfs initramfs file '%s'\n",
- initramfs_file);
+ pr_warning("No such hvfs initramfs file '%s'\n",
+ initramfs_file);
return;
}
BUG_ON(fd < 0);
stat = hv_fs_fstat(fd);
BUG_ON(stat.size < 0);
if (stat.flags & HV_FS_ISDIR) {
- printk("Ignoring hvfs file '%s': it's a directory.\n",
- initramfs_file);
+ pr_warning("Ignoring hvfs file '%s': it's a directory.\n",
+ initramfs_file);
return;
}
initrd = alloc_bootmem_pages(stat.size);
rc = hv_fs_pread(fd, (HV_VirtAddr) initrd, stat.size, 0);
if (rc != stat.size) {
- printk("Error reading %d bytes from hvfs file '%s': %d\n",
+ pr_err("Error reading %d bytes from hvfs file '%s': %d\n",
stat.size, initramfs_file, rc);
free_bootmem((unsigned long) initrd, stat.size);
return;
@@ -966,9 +980,9 @@ static void __init validate_hv(void)
HV_Topology topology = hv_inquire_topology();
BUG_ON(topology.coord.x != 0 || topology.coord.y != 0);
if (topology.width != 1 || topology.height != 1) {
- printk("Warning: booting UP kernel on %dx%d grid;"
- " will ignore all but first tile.\n",
- topology.width, topology.height);
+ pr_warning("Warning: booting UP kernel on %dx%d grid;"
+ " will ignore all but first tile.\n",
+ topology.width, topology.height);
}
#endif
@@ -1004,7 +1018,7 @@ static void __init validate_hv(void)
if (hv_confstr(HV_CONFSTR_CHIP_MODEL, (HV_VirtAddr)chip_model,
sizeof(chip_model)) < 0) {
- printk("Warning: HV_CONFSTR_CHIP_MODEL not available\n");
+ pr_err("Warning: HV_CONFSTR_CHIP_MODEL not available\n");
strlcpy(chip_model, "unknown", sizeof(chip_model));
}
}
@@ -1096,7 +1110,7 @@ static int __init disabled_cpus(char *str)
if (str == NULL || cpulist_parse_crop(str, &disabled_map) != 0)
return -EINVAL;
if (cpumask_test_cpu(boot_cpu, &disabled_map)) {
- printk("disabled_cpus: can't disable boot cpu %d\n", boot_cpu);
+ pr_err("disabled_cpus: can't disable boot cpu %d\n", boot_cpu);
cpumask_clear_cpu(boot_cpu, &disabled_map);
}
return 0;
@@ -1104,12 +1118,12 @@ static int __init disabled_cpus(char *str)
early_param("disabled_cpus", disabled_cpus);
-void __init print_disabled_cpus()
+void __init print_disabled_cpus(void)
{
if (!cpumask_empty(&disabled_map)) {
char buf[100];
cpulist_scnprintf(buf, sizeof(buf), &disabled_map);
- printk(KERN_INFO "CPUs not available for Linux: %s\n", buf);
+ pr_info("CPUs not available for Linux: %s\n", buf);
}
}
@@ -1162,7 +1176,7 @@ static void __init setup_cpu_maps(void)
(HV_VirtAddr) cpumask_bits(&cpu_lotar_map),
sizeof(cpu_lotar_map));
if (rc < 0) {
- printk("warning: no HV_INQ_TILES_LOTAR; using AVAIL\n");
+ pr_err("warning: no HV_INQ_TILES_LOTAR; using AVAIL\n");
cpu_lotar_map = cpu_possible_map;
}
@@ -1182,7 +1196,7 @@ static void __init setup_cpu_maps(void)
static int __init dataplane(char *str)
{
- printk("WARNING: dataplane support disabled in this kernel\n");
+ pr_warning("WARNING: dataplane support disabled in this kernel\n");
return 0;
}
@@ -1200,8 +1214,8 @@ void __init setup_arch(char **cmdline_p)
len = hv_get_command_line((HV_VirtAddr) boot_command_line,
COMMAND_LINE_SIZE);
if (boot_command_line[0])
- printk("WARNING: ignoring dynamic command line \"%s\"\n",
- boot_command_line);
+ pr_warning("WARNING: ignoring dynamic command line \"%s\"\n",
+ boot_command_line);
strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
#else
char *hv_cmdline;
@@ -1269,7 +1283,7 @@ void __init setup_arch(char **cmdline_p)
setup_numa_mapping();
zone_sizes_init();
set_page_homes();
- setup_mpls();
+ setup_cpu(1);
setup_clock();
load_hv_initrd();
}
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c
index 45835cfad40..45b66a3c991 100644
--- a/arch/tile/kernel/signal.c
+++ b/arch/tile/kernel/signal.c
@@ -33,6 +33,7 @@
#include <asm/processor.h>
#include <asm/ucontext.h>
#include <asm/sigframe.h>
+#include <asm/syscalls.h>
#include <arch/interrupts.h>
#define DEBUG_SIG 0
@@ -40,11 +41,8 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-/* Caller before callee in this file; other callee is in assembler */
-void do_signal(struct pt_regs *regs);
-
long _sys_sigaltstack(const stack_t __user *uss,
- stack_t __user *uoss, struct pt_regs *regs)
+ stack_t __user *uoss, struct pt_regs *regs)
{
return do_sigaltstack(uss, uoss, regs->sp);
}
@@ -65,7 +63,7 @@ int restore_sigcontext(struct pt_regs *regs,
for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i)
err |= __get_user(((long *)regs)[i],
- &((long *)(&sc->regs))[i]);
+ &((long __user *)(&sc->regs))[i]);
regs->faultnum = INT_SWINT_1_SIGRETURN;
@@ -73,7 +71,8 @@ int restore_sigcontext(struct pt_regs *regs,
return err;
}
-int _sys_rt_sigreturn(struct pt_regs *regs)
+/* sigreturn() returns long since it restores r0 in the interrupted code. */
+long _sys_rt_sigreturn(struct pt_regs *regs)
{
struct rt_sigframe __user *frame =
(struct rt_sigframe __user *)(regs->sp);
@@ -114,7 +113,7 @@ int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs)
for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i)
err |= __put_user(((long *)regs)[i],
- &((long *)(&sc->regs))[i]);
+ &((long __user *)(&sc->regs))[i]);
return err;
}
@@ -137,7 +136,7 @@ static inline void __user *get_sigframe(struct k_sigaction *ka,
* will die with SIGSEGV.
*/
if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size)))
- return (void __user *) -1L;
+ return (void __user __force *)-1UL;
/* This is the X/Open sanctioned signal stack switching. */
if (ka->sa.sa_flags & SA_ONSTACK) {
@@ -185,8 +184,8 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Create the ucontext. */
err |= __clear_user(&frame->save_area, sizeof(frame->save_area));
err |= __put_user(0, &frame->uc.uc_flags);
- err |= __put_user(0, &frame->uc.uc_link);
- err |= __put_user((void *)(current->sas_ss_sp),
+ err |= __put_user(NULL, &frame->uc.uc_link);
+ err |= __put_user((void __user *)(current->sas_ss_sp),
&frame->uc.uc_stack.ss_sp);
err |= __put_user(sas_ss_flags(regs->sp),
&frame->uc.uc_stack.ss_flags);
diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c
index 266aae12363..5ec4b9c651f 100644
--- a/arch/tile/kernel/single_step.c
+++ b/arch/tile/kernel/single_step.c
@@ -23,6 +23,7 @@
#include <linux/uaccess.h>
#include <linux/mman.h>
#include <linux/types.h>
+#include <linux/err.h>
#include <asm/cacheflush.h>
#include <asm/opcode-tile.h>
#include <asm/opcode_constants.h>
@@ -39,8 +40,8 @@ static int __init setup_unaligned_printk(char *str)
if (strict_strtol(str, 0, &val) != 0)
return 0;
unaligned_printk = val;
- printk("Printk for each unaligned data accesses is %s\n",
- unaligned_printk ? "enabled" : "disabled");
+ pr_info("Printk for each unaligned data accesses is %s\n",
+ unaligned_printk ? "enabled" : "disabled");
return 1;
}
__setup("unaligned_printk=", setup_unaligned_printk);
@@ -113,7 +114,7 @@ static tile_bundle_bits rewrite_load_store_unaligned(
enum mem_op mem_op,
int size, int sign_ext)
{
- unsigned char *addr;
+ unsigned char __user *addr;
int val_reg, addr_reg, err, val;
/* Get address and value registers */
@@ -148,7 +149,7 @@ static tile_bundle_bits rewrite_load_store_unaligned(
return bundle;
/* If it's aligned, don't handle it specially */
- addr = (void *)regs->regs[addr_reg];
+ addr = (void __user *)regs->regs[addr_reg];
if (((unsigned long)addr % size) == 0)
return bundle;
@@ -183,7 +184,7 @@ static tile_bundle_bits rewrite_load_store_unaligned(
siginfo_t info = {
.si_signo = SIGSEGV,
.si_code = SEGV_MAPERR,
- .si_addr = (void __user *)addr
+ .si_addr = addr
};
force_sig_info(info.si_signo, &info, current);
return (tile_bundle_bits) 0;
@@ -193,30 +194,33 @@ static tile_bundle_bits rewrite_load_store_unaligned(
siginfo_t info = {
.si_signo = SIGBUS,
.si_code = BUS_ADRALN,
- .si_addr = (void __user *)addr
+ .si_addr = addr
};
force_sig_info(info.si_signo, &info, current);
return (tile_bundle_bits) 0;
}
if (unaligned_printk || unaligned_fixup_count == 0) {
- printk("Process %d/%s: PC %#lx: Fixup of"
- " unaligned %s at %#lx.\n",
- current->pid, current->comm, regs->pc,
- (mem_op == MEMOP_LOAD || mem_op == MEMOP_LOAD_POSTINCR) ?
- "load" : "store",
- (unsigned long)addr);
+ pr_info("Process %d/%s: PC %#lx: Fixup of"
+ " unaligned %s at %#lx.\n",
+ current->pid, current->comm, regs->pc,
+ (mem_op == MEMOP_LOAD ||
+ mem_op == MEMOP_LOAD_POSTINCR) ?
+ "load" : "store",
+ (unsigned long)addr);
if (!unaligned_printk) {
- printk("\n"
-"Unaligned fixups in the kernel will slow your application considerably.\n"
-"You can find them by writing \"1\" to /proc/sys/tile/unaligned_fixup/printk,\n"
-"which requests the kernel show all unaligned fixups, or writing a \"0\"\n"
-"to /proc/sys/tile/unaligned_fixup/enabled, in which case each unaligned\n"
-"access will become a SIGBUS you can debug. No further warnings will be\n"
-"shown so as to avoid additional slowdown, but you can track the number\n"
-"of fixups performed via /proc/sys/tile/unaligned_fixup/count.\n"
-"Use the tile-addr2line command (see \"info addr2line\") to decode PCs.\n"
- "\n");
+#define P pr_info
+P("\n");
+P("Unaligned fixups in the kernel will slow your application considerably.\n");
+P("To find them, write a \"1\" to /proc/sys/tile/unaligned_fixup/printk,\n");
+P("which requests the kernel show all unaligned fixups, or write a \"0\"\n");
+P("to /proc/sys/tile/unaligned_fixup/enabled, in which case each unaligned\n");
+P("access will become a SIGBUS you can debug. No further warnings will be\n");
+P("shown so as to avoid additional slowdown, but you can track the number\n");
+P("of fixups performed via /proc/sys/tile/unaligned_fixup/count.\n");
+P("Use the tile-addr2line command (see \"info addr2line\") to decode PCs.\n");
+P("\n");
+#undef P
}
}
++unaligned_fixup_count;
@@ -276,7 +280,7 @@ void single_step_once(struct pt_regs *regs)
struct thread_info *info = (void *)current_thread_info();
struct single_step_state *state = info->step_state;
int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP);
- tile_bundle_bits *buffer, *pc;
+ tile_bundle_bits __user *buffer, *pc;
tile_bundle_bits bundle;
int temp_reg;
int target_reg = TREG_LR;
@@ -306,21 +310,21 @@ void single_step_once(struct pt_regs *regs)
/* allocate a page of writable, executable memory */
state = kmalloc(sizeof(struct single_step_state), GFP_KERNEL);
if (state == NULL) {
- printk("Out of kernel memory trying to single-step\n");
+ pr_err("Out of kernel memory trying to single-step\n");
return;
}
/* allocate a cache line of writable, executable memory */
down_write(&current->mm->mmap_sem);
- buffer = (void *) do_mmap(0, 0, 64,
+ buffer = (void __user *) do_mmap(NULL, 0, 64,
PROT_EXEC | PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
0);
up_write(&current->mm->mmap_sem);
- if ((int)buffer < 0 && (int)buffer > -PAGE_SIZE) {
+ if (IS_ERR((void __force *)buffer)) {
kfree(state);
- printk("Out of kernel pages trying to single-step\n");
+ pr_err("Out of kernel pages trying to single-step\n");
return;
}
@@ -349,11 +353,14 @@ void single_step_once(struct pt_regs *regs)
if (regs->faultnum == INT_SWINT_1)
regs->pc -= 8;
- pc = (tile_bundle_bits *)(regs->pc);
- bundle = pc[0];
+ pc = (tile_bundle_bits __user *)(regs->pc);
+ if (get_user(bundle, pc) != 0) {
+ pr_err("Couldn't read instruction at %p trying to step\n", pc);
+ return;
+ }
/* We'll follow the instruction with 2 ill op bundles */
- state->orig_pc = (unsigned long) pc;
+ state->orig_pc = (unsigned long)pc;
state->next_pc = (unsigned long)(pc + 1);
state->branch_next_pc = 0;
state->update = 0;
@@ -633,7 +640,7 @@ void single_step_once(struct pt_regs *regs)
}
if (err) {
- printk("Fault when writing to single-step buffer\n");
+ pr_err("Fault when writing to single-step buffer\n");
return;
}
@@ -641,12 +648,12 @@ void single_step_once(struct pt_regs *regs)
* Flush the buffer.
* We do a local flush only, since this is a thread-specific buffer.
*/
- __flush_icache_range((unsigned long) state->buffer,
- (unsigned long) buffer);
+ __flush_icache_range((unsigned long)state->buffer,
+ (unsigned long)buffer);
/* Indicate enabled */
state->is_enabled = is_single_step;
- regs->pc = (unsigned long) state->buffer;
+ regs->pc = (unsigned long)state->buffer;
/* Fault immediately if we are coming back from a syscall. */
if (regs->faultnum == INT_SWINT_1)
diff --git a/arch/tile/kernel/smpboot.c b/arch/tile/kernel/smpboot.c
index aa3aafdb4b9..74d62d098ed 100644
--- a/arch/tile/kernel/smpboot.c
+++ b/arch/tile/kernel/smpboot.c
@@ -25,19 +25,13 @@
#include <linux/percpu.h>
#include <linux/delay.h>
#include <linux/err.h>
+#include <linux/irq.h>
#include <asm/mmu_context.h>
#include <asm/tlbflush.h>
#include <asm/sections.h>
-/*
- * This assembly function is provided in entry.S.
- * When called, it loops on a nap instruction forever.
- * FIXME: should be in a header somewhere.
- */
-extern void smp_nap(void);
-
/* State of each CPU. */
-DEFINE_PER_CPU(int, cpu_state) = { 0 };
+static DEFINE_PER_CPU(int, cpu_state) = { 0 };
/* The messaging code jumps to this pointer during boot-up */
unsigned long start_cpu_function_addr;
@@ -74,7 +68,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
*/
rc = sched_setaffinity(current->pid, cpumask_of(boot_cpu));
if (rc != 0)
- printk("Couldn't set init affinity to boot cpu (%ld)\n", rc);
+ pr_err("Couldn't set init affinity to boot cpu (%ld)\n", rc);
/* Print information about disabled and dataplane cpus. */
print_disabled_cpus();
@@ -134,13 +128,13 @@ static __init int reset_init_affinity(void)
{
long rc = sched_setaffinity(current->pid, &init_affinity);
if (rc != 0)
- printk(KERN_WARNING "couldn't reset init affinity (%ld)\n",
+ pr_warning("couldn't reset init affinity (%ld)\n",
rc);
return 0;
}
late_initcall(reset_init_affinity);
-struct cpumask cpu_started __cpuinitdata;
+static struct cpumask cpu_started __cpuinitdata;
/*
* Activate a secondary processor. Very minimal; don't add anything
@@ -172,9 +166,6 @@ static void __cpuinit start_secondary(void)
BUG();
enter_lazy_tlb(&init_mm, current);
- /* Enable IRQs. */
- init_per_tile_IRQs();
-
/* Allow hypervisor messages to be received */
init_messaging();
local_irq_enable();
@@ -182,7 +173,7 @@ static void __cpuinit start_secondary(void)
/* Indicate that we're ready to come up. */
/* Must not do this before we're ready to receive messages */
if (cpumask_test_and_set_cpu(cpuid, &cpu_started)) {
- printk(KERN_WARNING "CPU#%d already started!\n", cpuid);
+ pr_warning("CPU#%d already started!\n", cpuid);
for (;;)
local_irq_enable();
}
@@ -190,13 +181,10 @@ static void __cpuinit start_secondary(void)
smp_nap();
}
-void setup_mpls(void); /* from kernel/setup.c */
-void store_permanent_mappings(void);
-
/*
* Bring a secondary processor online.
*/
-void __cpuinit online_secondary()
+void __cpuinit online_secondary(void)
{
/*
* low-memory mappings have been cleared, flush them from
@@ -222,17 +210,14 @@ void __cpuinit online_secondary()
ipi_call_unlock();
__get_cpu_var(cpu_state) = CPU_ONLINE;
- /* Set up MPLs for this processor */
- setup_mpls();
-
+ /* Set up tile-specific state for this cpu. */
+ setup_cpu(0);
/* Set up tile-timer clock-event device on this cpu */
setup_tile_timer();
preempt_enable();
- store_permanent_mappings();
-
cpu_idle();
}
@@ -242,7 +227,7 @@ int __cpuinit __cpu_up(unsigned int cpu)
static int timeout;
for (; !cpumask_test_cpu(cpu, &cpu_started); timeout++) {
if (timeout >= 50000) {
- printk(KERN_INFO "skipping unresponsive cpu%d\n", cpu);
+ pr_info("skipping unresponsive cpu%d\n", cpu);
local_irq_enable();
return -EIO;
}
@@ -289,5 +274,5 @@ void __init smp_cpus_done(unsigned int max_cpus)
;
rc = sched_setaffinity(current->pid, cpumask_of(cpu));
if (rc != 0)
- printk("Couldn't set init affinity to cpu %d (%d)\n", cpu, rc);
+ pr_err("Couldn't set init affinity to cpu %d (%d)\n", cpu, rc);
}
diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c
index 382170b4b40..b6268d3ae86 100644
--- a/arch/tile/kernel/stack.c
+++ b/arch/tile/kernel/stack.c
@@ -56,13 +56,16 @@ static int valid_address(struct KBacktraceIterator *kbt, VirtualAddress address)
HV_PTE pte;
struct page *page;
+ if (l1_pgtable == NULL)
+ return 0; /* can't read user space in other tasks */
+
pte = l1_pgtable[HV_L1_INDEX(address)];
if (!hv_pte_get_present(pte))
return 0;
pfn = hv_pte_get_pfn(pte);
if (pte_huge(pte)) {
if (!pfn_valid(pfn)) {
- printk(KERN_ERR "huge page has bad pfn %#lx\n", pfn);
+ pr_err("huge page has bad pfn %#lx\n", pfn);
return 0;
}
return hv_pte_get_present(pte) && hv_pte_get_readable(pte);
@@ -70,7 +73,7 @@ static int valid_address(struct KBacktraceIterator *kbt, VirtualAddress address)
page = pfn_to_page(pfn);
if (PageHighMem(page)) {
- printk(KERN_ERR "L2 page table not in LOWMEM (%#llx)\n",
+ pr_err("L2 page table not in LOWMEM (%#llx)\n",
HV_PFN_TO_CPA(pfn));
return 0;
}
@@ -91,13 +94,12 @@ static bool read_memory_func(void *result, VirtualAddress address,
/* We only tolerate kernel-space reads of this task's stack */
if (!in_kernel_stack(kbt, address))
return 0;
- } else if (kbt->pgtable == NULL) {
- return 0; /* can't read user space in other tasks */
} else if (!valid_address(kbt, address)) {
return 0; /* invalid user-space address */
}
pagefault_disable();
- retval = __copy_from_user_inatomic(result, (const void *)address,
+ retval = __copy_from_user_inatomic(result,
+ (void __user __force *)address,
size);
pagefault_enable();
return (retval == 0);
@@ -131,14 +133,14 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
in_kernel_stack(kbt, p->sp) &&
p->sp >= sp) {
if (kbt->verbose)
- printk(KERN_ERR " <%s while in kernel mode>\n", fault);
+ pr_err(" <%s while in kernel mode>\n", fault);
} else if (EX1_PL(p->ex1) == USER_PL &&
p->pc < PAGE_OFFSET &&
p->sp < PAGE_OFFSET) {
if (kbt->verbose)
- printk(KERN_ERR " <%s while in user mode>\n", fault);
+ pr_err(" <%s while in user mode>\n", fault);
} else if (kbt->verbose) {
- printk(KERN_ERR " (odd fault: pc %#lx, sp %#lx, ex1 %#lx?)\n",
+ pr_err(" (odd fault: pc %#lx, sp %#lx, ex1 %#lx?)\n",
p->pc, p->sp, p->ex1);
p = NULL;
}
@@ -166,13 +168,13 @@ static struct pt_regs *valid_sigframe(struct KBacktraceIterator* kbt)
if (!valid_address(kbt, b->sp) ||
!valid_address(kbt, sigframe_top)) {
if (kbt->verbose)
- printk(" (odd signal: sp %#lx?)\n",
+ pr_err(" (odd signal: sp %#lx?)\n",
(unsigned long)(b->sp));
return NULL;
}
frame = (struct rt_sigframe *)b->sp;
if (kbt->verbose) {
- printk(KERN_ERR " <received signal %d>\n",
+ pr_err(" <received signal %d>\n",
frame->info.si_signo);
}
return &frame->uc.uc_mcontext.regs;
@@ -180,7 +182,7 @@ static struct pt_regs *valid_sigframe(struct KBacktraceIterator* kbt)
return NULL;
}
-int KBacktraceIterator_is_sigreturn(struct KBacktraceIterator *kbt)
+static int KBacktraceIterator_is_sigreturn(struct KBacktraceIterator *kbt)
{
return is_sigreturn(kbt->it.pc);
}
@@ -231,13 +233,13 @@ static void validate_stack(struct pt_regs *regs)
unsigned long sp = stack_pointer;
if (EX1_PL(regs->ex1) == KERNEL_PL && regs->sp >= ksp0) {
- printk("WARNING: cpu %d: kernel stack page %#lx underrun!\n"
+ pr_err("WARNING: cpu %d: kernel stack page %#lx underrun!\n"
" sp %#lx (%#lx in caller), caller pc %#lx, lr %#lx\n",
cpu, ksp0_base, sp, regs->sp, regs->pc, regs->lr);
}
else if (sp < ksp0_base + sizeof(struct thread_info)) {
- printk("WARNING: cpu %d: kernel stack page %#lx overrun!\n"
+ pr_err("WARNING: cpu %d: kernel stack page %#lx overrun!\n"
" sp %#lx (%#lx in caller), caller pc %#lx, lr %#lx\n",
cpu, ksp0_base, sp, regs->sp, regs->pc, regs->lr);
}
@@ -280,7 +282,7 @@ void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
if (!PageHighMem(page))
kbt->pgtable = __va(pgdir_pa);
else
- printk(KERN_ERR "page table not in LOWMEM"
+ pr_err("page table not in LOWMEM"
" (%#llx)\n", pgdir_pa);
}
local_flush_tlb_all();
@@ -288,13 +290,12 @@ void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
}
if (regs == NULL) {
- extern const void *get_switch_to_pc(void);
if (is_current || t->state == TASK_RUNNING) {
/* Can't do this; we need registers */
kbt->end = 1;
return;
}
- pc = (ulong) get_switch_to_pc();
+ pc = get_switch_to_pc();
lr = t->thread.pc;
sp = t->thread.ksp;
r52 = 0;
@@ -344,8 +345,8 @@ void tile_show_stack(struct KBacktraceIterator *kbt, int headers)
* then bust_spinlocks() spit out a space in front of us
* and it will mess up our KERN_ERR.
*/
- printk("\n");
- printk(KERN_ERR "Starting stack dump of tid %d, pid %d (%s)"
+ pr_err("\n");
+ pr_err("Starting stack dump of tid %d, pid %d (%s)"
" on cpu %d at cycle %lld\n",
kbt->task->pid, kbt->task->tgid, kbt->task->comm,
smp_processor_id(), get_cycles());
@@ -385,17 +386,17 @@ void tile_show_stack(struct KBacktraceIterator *kbt, int headers)
namebuf[sizeof(namebuf)-1] = '\0';
}
- printk(KERN_ERR " frame %d: 0x%lx %s(sp 0x%lx)\n",
+ pr_err(" frame %d: 0x%lx %s(sp 0x%lx)\n",
i++, address, namebuf, (unsigned long)(kbt->it.sp));
if (i >= 100) {
- printk(KERN_ERR "Stack dump truncated"
+ pr_err("Stack dump truncated"
" (%d frames)\n", i);
break;
}
}
if (headers)
- printk(KERN_ERR "Stack dump complete\n");
+ pr_err("Stack dump complete\n");
}
EXPORT_SYMBOL(tile_show_stack);
diff --git a/arch/tile/kernel/sys.c b/arch/tile/kernel/sys.c
index 0427978cea0..f0f87eab8c3 100644
--- a/arch/tile/kernel/sys.c
+++ b/arch/tile/kernel/sys.c
@@ -27,11 +27,10 @@
#include <linux/mempolicy.h>
#include <linux/binfmts.h>
#include <linux/fs.h>
-#include <linux/syscalls.h>
+#include <linux/compat.h>
#include <linux/uaccess.h>
#include <linux/signal.h>
#include <asm/syscalls.h>
-
#include <asm/pgtable.h>
#include <asm/homecache.h>
#include <arch/chip.h>
@@ -74,10 +73,7 @@ int sys32_fadvise64_64(int fd, u32 offset_lo, u32 offset_hi,
#endif /* 32-bit syscall wrappers */
-/*
- * This API uses a 4KB-page-count offset into the file descriptor.
- * It is likely not the right API to use on a 64-bit platform.
- */
+/* Note: used by the compat code even in 64-bit Linux. */
SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len,
unsigned long, prot, unsigned long, flags,
unsigned long, fd, unsigned long, off_4k)
@@ -89,10 +85,7 @@ SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len,
off_4k >> PAGE_ADJUST);
}
-/*
- * This API uses a byte offset into the file descriptor.
- * It is likely not the right API to use on a 32-bit platform.
- */
+#ifdef __tilegx__
SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
unsigned long, prot, unsigned long, flags,
unsigned long, fd, off_t, offset)
@@ -102,6 +95,7 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
return sys_mmap_pgoff(addr, len, prot, flags, fd,
offset >> PAGE_SHIFT);
}
+#endif
/* Provide the actual syscall number to call mapping. */
@@ -116,6 +110,10 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
#define sys_sync_file_range sys_sync_file_range2
#endif
+/*
+ * Note that we can't include <linux/unistd.h> here since the header
+ * guard will defeat us; <asm/unistd.h> checks for __SYSCALL as well.
+ */
void *sys_call_table[__NR_syscalls] = {
[0 ... __NR_syscalls-1] = sys_ni_syscall,
#include <asm/unistd.h>
diff --git a/arch/tile/kernel/time.c b/arch/tile/kernel/time.c
index 47500a324e3..b9ab25a889b 100644
--- a/arch/tile/kernel/time.c
+++ b/arch/tile/kernel/time.c
@@ -23,6 +23,7 @@
#include <linux/smp.h>
#include <linux/delay.h>
#include <asm/irq_regs.h>
+#include <asm/traps.h>
#include <hv/hypervisor.h>
#include <arch/interrupts.h>
#include <arch/spr_def.h>
@@ -45,13 +46,13 @@ static cycles_t cycles_per_sec __write_once;
*/
#define TILE_MINSEC 5
-cycles_t get_clock_rate()
+cycles_t get_clock_rate(void)
{
return cycles_per_sec;
}
#if CHIP_HAS_SPLIT_CYCLE()
-cycles_t get_cycles()
+cycles_t get_cycles(void)
{
unsigned int high = __insn_mfspr(SPR_CYCLE_HIGH);
unsigned int low = __insn_mfspr(SPR_CYCLE_LOW);
@@ -67,7 +68,7 @@ cycles_t get_cycles()
}
#endif
-cycles_t clocksource_get_cycles(struct clocksource *cs)
+static cycles_t clocksource_get_cycles(struct clocksource *cs)
{
return get_cycles();
}
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c
index 12cb10f3852..3870abbeeaa 100644
--- a/arch/tile/kernel/traps.c
+++ b/arch/tile/kernel/traps.c
@@ -20,6 +20,9 @@
#include <linux/uaccess.h>
#include <linux/ptrace.h>
#include <asm/opcode-tile.h>
+#include <asm/opcode_constants.h>
+#include <asm/stack.h>
+#include <asm/traps.h>
#include <arch/interrupts.h>
#include <arch/spr_def.h>
@@ -42,7 +45,7 @@ static int __init setup_unaligned_fixup(char *str)
if (strict_strtol(str, 0, &val) != 0)
return 0;
unaligned_fixup = val;
- printk("Fixups for unaligned data accesses are %s\n",
+ pr_info("Fixups for unaligned data accesses are %s\n",
unaligned_fixup >= 0 ?
(unaligned_fixup ? "enabled" : "disabled") :
"completely disabled");
@@ -56,7 +59,7 @@ static int dma_disabled;
static int __init nodma(char *str)
{
- printk("User-space DMA is disabled\n");
+ pr_info("User-space DMA is disabled\n");
dma_disabled = 1;
return 1;
}
@@ -97,20 +100,106 @@ static int retry_gpv(unsigned int gpv_reason)
#endif /* CHIP_HAS_TILE_DMA() */
-/* Defined inside do_trap(), below. */
#ifdef __tilegx__
-extern tilegx_bundle_bits bpt_code;
+#define bundle_bits tilegx_bundle_bits
#else
-extern tile_bundle_bits bpt_code;
+#define bundle_bits tile_bundle_bits
#endif
+extern bundle_bits bpt_code;
+
+asm(".pushsection .rodata.bpt_code,\"a\";"
+ ".align 8;"
+ "bpt_code: bpt;"
+ ".size bpt_code,.-bpt_code;"
+ ".popsection");
+
+static int special_ill(bundle_bits bundle, int *sigp, int *codep)
+{
+ int sig, code, maxcode;
+
+ if (bundle == bpt_code) {
+ *sigp = SIGTRAP;
+ *codep = TRAP_BRKPT;
+ return 1;
+ }
+
+ /* If it's a "raise" bundle, then "ill" must be in pipe X1. */
+#ifdef __tilegx__
+ if ((bundle & TILEGX_BUNDLE_MODE_MASK) != 0)
+ return 0;
+ if (get_Opcode_X1(bundle) != UNARY_OPCODE_X1)
+ return 0;
+ if (get_UnaryOpcodeExtension_X1(bundle) != ILL_UNARY_OPCODE_X1)
+ return 0;
+#else
+ if (bundle & TILE_BUNDLE_Y_ENCODING_MASK)
+ return 0;
+ if (get_Opcode_X1(bundle) != SHUN_0_OPCODE_X1)
+ return 0;
+ if (get_UnShOpcodeExtension_X1(bundle) != UN_0_SHUN_0_OPCODE_X1)
+ return 0;
+ if (get_UnOpcodeExtension_X1(bundle) != ILL_UN_0_SHUN_0_OPCODE_X1)
+ return 0;
+#endif
+
+ /* Check that the magic distinguishers are set to mean "raise". */
+ if (get_Dest_X1(bundle) != 29 || get_SrcA_X1(bundle) != 37)
+ return 0;
+
+ /* There must be an "addli zero, zero, VAL" in X0. */
+ if (get_Opcode_X0(bundle) != ADDLI_OPCODE_X0)
+ return 0;
+ if (get_Dest_X0(bundle) != TREG_ZERO)
+ return 0;
+ if (get_SrcA_X0(bundle) != TREG_ZERO)
+ return 0;
+
+ /*
+ * Validate the proposed signal number and si_code value.
+ * Note that we embed these in the static instruction itself
+ * so that we perturb the register state as little as possible
+ * at the time of the actual fault; it's unlikely you'd ever
+ * need to dynamically choose which kind of fault to raise
+ * from user space.
+ */
+ sig = get_Imm16_X0(bundle) & 0x3f;
+ switch (sig) {
+ case SIGILL:
+ maxcode = NSIGILL;
+ break;
+ case SIGFPE:
+ maxcode = NSIGFPE;
+ break;
+ case SIGSEGV:
+ maxcode = NSIGSEGV;
+ break;
+ case SIGBUS:
+ maxcode = NSIGBUS;
+ break;
+ case SIGTRAP:
+ maxcode = NSIGTRAP;
+ break;
+ default:
+ return 0;
+ }
+ code = (get_Imm16_X0(bundle) >> 6) & 0xf;
+ if (code <= 0 || code > maxcode)
+ return 0;
+
+ /* Make it the requested signal. */
+ *sigp = sig;
+ *codep = code | __SI_FAULT;
+ return 1;
+}
+
void __kprobes do_trap(struct pt_regs *regs, int fault_num,
unsigned long reason)
{
siginfo_t info = { 0 };
int signo, code;
unsigned long address;
- __typeof__(bpt_code) instr;
+ bundle_bits instr;
/* Re-enable interrupts. */
local_irq_enable();
@@ -122,10 +211,10 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
if (!user_mode(regs)) {
if (fixup_exception(regs)) /* only UNALIGN_DATA in practice */
return;
- printk(KERN_ALERT "Kernel took bad trap %d at PC %#lx\n",
+ pr_alert("Kernel took bad trap %d at PC %#lx\n",
fault_num, regs->pc);
if (fault_num == INT_GPV)
- printk(KERN_ALERT "GPV_REASON is %#lx\n", reason);
+ pr_alert("GPV_REASON is %#lx\n", reason);
show_regs(regs);
do_exit(SIGKILL); /* FIXME: implement i386 die() */
return;
@@ -133,22 +222,14 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
switch (fault_num) {
case INT_ILL:
- asm(".pushsection .rodata.bpt_code,\"a\";"
- ".align 8;"
- "bpt_code: bpt;"
- ".size bpt_code,.-bpt_code;"
- ".popsection");
-
- if (copy_from_user(&instr, (void *)regs->pc, sizeof(instr))) {
- printk(KERN_ERR "Unreadable instruction for INT_ILL:"
+ if (copy_from_user(&instr, (void __user *)regs->pc,
+ sizeof(instr))) {
+ pr_err("Unreadable instruction for INT_ILL:"
" %#lx\n", regs->pc);
do_exit(SIGKILL);
return;
}
- if (instr == bpt_code) {
- signo = SIGTRAP;
- code = TRAP_BRKPT;
- } else {
+ if (!special_ill(instr, &signo, &code)) {
signo = SIGILL;
code = ILL_ILLOPC;
}
@@ -181,7 +262,8 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
if (unaligned_fixup >= 0) {
struct single_step_state *state =
current_thread_info()->step_state;
- if (!state || (void *)(regs->pc) != state->buffer) {
+ if (!state ||
+ (void __user *)(regs->pc) != state->buffer) {
single_step_once(regs);
return;
}
@@ -221,17 +303,15 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
info.si_signo = signo;
info.si_code = code;
- info.si_addr = (void *)address;
+ info.si_addr = (void __user *)address;
if (signo == SIGILL)
info.si_trapno = fault_num;
force_sig_info(signo, &info, current);
}
-extern void _dump_stack(int dummy, ulong pc, ulong lr, ulong sp, ulong r52);
-
void kernel_double_fault(int dummy, ulong pc, ulong lr, ulong sp, ulong r52)
{
_dump_stack(dummy, pc, lr, sp, r52);
- printk("Double fault: exiting\n");
+ pr_emerg("Double fault: exiting\n");
machine_halt();
}
diff --git a/arch/tile/kernel/vmlinux.lds.S b/arch/tile/kernel/vmlinux.lds.S
index 77388c1415b..25fdc0c1839 100644
--- a/arch/tile/kernel/vmlinux.lds.S
+++ b/arch/tile/kernel/vmlinux.lds.S
@@ -36,8 +36,8 @@ SECTIONS
/* Now the real code */
. = ALIGN(0x20000);
- HEAD_TEXT_SECTION :text =0
.text : AT (ADDR(.text) - LOAD_OFFSET) {
+ HEAD_TEXT
SCHED_TEXT
LOCK_TEXT
__fix_text_end = .; /* tile-cpack won't rearrange before this */
@@ -46,7 +46,7 @@ SECTIONS
*(.coldtext*)
*(.fixup)
*(.gnu.warning)
- }
+ } :text =0
_etext = .;
/* "Init" is divided into two areas with very different virtual addresses. */