diff options
Diffstat (limited to 'arch/tile/kernel')
-rw-r--r-- | arch/tile/kernel/backtrace.c | 81 | ||||
-rw-r--r-- | arch/tile/kernel/compat.c | 28 | ||||
-rw-r--r-- | arch/tile/kernel/compat_signal.c | 10 | ||||
-rw-r--r-- | arch/tile/kernel/early_printk.c | 2 | ||||
-rw-r--r-- | arch/tile/kernel/entry.S | 4 | ||||
-rw-r--r-- | arch/tile/kernel/machine_kexec.c | 38 | ||||
-rw-r--r-- | arch/tile/kernel/messaging.c | 5 | ||||
-rw-r--r-- | arch/tile/kernel/module.c | 16 | ||||
-rw-r--r-- | arch/tile/kernel/process.c | 110 | ||||
-rw-r--r-- | arch/tile/kernel/ptrace.c | 3 | ||||
-rw-r--r-- | arch/tile/kernel/reboot.c | 7 | ||||
-rw-r--r-- | arch/tile/kernel/setup.c | 132 | ||||
-rw-r--r-- | arch/tile/kernel/signal.c | 19 | ||||
-rw-r--r-- | arch/tile/kernel/single_step.c | 75 | ||||
-rw-r--r-- | arch/tile/kernel/smpboot.c | 37 | ||||
-rw-r--r-- | arch/tile/kernel/stack.c | 43 | ||||
-rw-r--r-- | arch/tile/kernel/sys.c | 18 | ||||
-rw-r--r-- | arch/tile/kernel/time.c | 7 | ||||
-rw-r--r-- | arch/tile/kernel/traps.c | 130 | ||||
-rw-r--r-- | arch/tile/kernel/vmlinux.lds.S | 4 |
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(¤t->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(¤t->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. */ |