From f419e6f63c5afea00d7c17ebf54f2d265f5c4d7e Mon Sep 17 00:00:00 2001 From: Zhigang Lu Date: Wed, 30 Sep 2015 09:53:47 +0800 Subject: tile: define a macro ktext_writable_addr to get writable kernel text address It is used by kgdb, ftrace, kprobe and jump label, so we factor this out into a helper routine. Reviewed-by: Chris Metcalf Signed-off-by: Zhigang Lu Signed-off-by: Chris Metcalf diff --git a/arch/tile/include/asm/page.h b/arch/tile/include/asm/page.h index a213a8d..5cee2cb 100644 --- a/arch/tile/include/asm/page.h +++ b/arch/tile/include/asm/page.h @@ -319,6 +319,16 @@ static inline int pfn_valid(unsigned long pfn) #define virt_to_page(kaddr) pfn_to_page(kaddr_to_pfn((void *)(kaddr))) #define page_to_virt(page) pfn_to_kaddr(page_to_pfn(page)) +/* + * The kernel text is mapped at MEM_SV_START as read-only. To allow + * modifying kernel text, it is also mapped at PAGE_OFFSET as read-write. + * This macro converts a kernel address to its writable kernel text mapping, + * which is used to modify the text code on a running kernel by kgdb, + * ftrace, kprobe, jump label, etc. + */ +#define ktext_writable_addr(kaddr) \ + ((unsigned long)(kaddr) - MEM_SV_START + PAGE_OFFSET) + struct mm_struct; extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr); extern pte_t *virt_to_kpte(unsigned long kaddr); diff --git a/arch/tile/kernel/ftrace.c b/arch/tile/kernel/ftrace.c index 0c09961..4180ccdf 100644 --- a/arch/tile/kernel/ftrace.c +++ b/arch/tile/kernel/ftrace.c @@ -117,7 +117,7 @@ static int ftrace_modify_code(unsigned long pc, unsigned long old, return -EINVAL; /* Operate on writable kernel text mapping. */ - pc_wr = pc - MEM_SV_START + PAGE_OFFSET; + pc_wr = ktext_writable_addr(pc); if (probe_kernel_write((void *)pc_wr, &new, MCOUNT_INSN_SIZE)) return -EPERM; diff --git a/arch/tile/kernel/kgdb.c b/arch/tile/kernel/kgdb.c index ff5335a..a506c2c 100644 --- a/arch/tile/kernel/kgdb.c +++ b/arch/tile/kernel/kgdb.c @@ -164,7 +164,7 @@ static unsigned long writable_address(unsigned long addr) unsigned long ret = 0; if (core_kernel_text(addr)) - ret = addr - MEM_SV_START + PAGE_OFFSET; + ret = ktext_writable_addr(addr); else if (is_module_text_address(addr)) ret = addr; else diff --git a/arch/tile/kernel/kprobes.c b/arch/tile/kernel/kprobes.c index f8a45c5..c68694b 100644 --- a/arch/tile/kernel/kprobes.c +++ b/arch/tile/kernel/kprobes.c @@ -116,7 +116,7 @@ void __kprobes arch_arm_kprobe(struct kprobe *p) unsigned long addr_wr; /* Operate on writable kernel text mapping. */ - addr_wr = (unsigned long)p->addr - MEM_SV_START + PAGE_OFFSET; + addr_wr = ktext_writable_addr(p->addr); if (probe_kernel_write((void *)addr_wr, &breakpoint_insn, sizeof(breakpoint_insn))) @@ -131,7 +131,7 @@ void __kprobes arch_disarm_kprobe(struct kprobe *kp) unsigned long addr_wr; /* Operate on writable kernel text mapping. */ - addr_wr = (unsigned long)kp->addr - MEM_SV_START + PAGE_OFFSET; + addr_wr = ktext_writable_addr(kp->addr); if (probe_kernel_write((void *)addr_wr, &kp->opcode, sizeof(kp->opcode))) -- cgit v0.10.2 From 65a792e84f25d1436698f999224b2cf5d7594546 Mon Sep 17 00:00:00 2001 From: Zhigang Lu Date: Wed, 30 Sep 2015 10:11:45 +0800 Subject: tile/jump_label: add jump label support for TILE-Gx Add the arch-specific code to support jump label for TILE-Gx. This code shares NOP instruction with ftrace, so we move it to a common header file. Reviewed-by: Chris Metcalf Signed-off-by: Zhigang Lu Signed-off-by: Chris Metcalf diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index 106c21b..49be476 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig @@ -143,6 +143,7 @@ config TILEGX select HAVE_KRETPROBES select HAVE_ARCH_KGDB select ARCH_SUPPORTS_ATOMIC_RMW + select HAVE_ARCH_JUMP_LABEL config TILEPRO def_bool !TILEGX diff --git a/arch/tile/include/asm/insn.h b/arch/tile/include/asm/insn.h new file mode 100644 index 0000000..f78ba5c --- /dev/null +++ b/arch/tile/include/asm/insn.h @@ -0,0 +1,59 @@ +/* + * Copyright 2015 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ +#ifndef __ASM_TILE_INSN_H +#define __ASM_TILE_INSN_H + +#include + +static inline tilegx_bundle_bits NOP(void) +{ + return create_UnaryOpcodeExtension_X0(FNOP_UNARY_OPCODE_X0) | + create_RRROpcodeExtension_X0(UNARY_RRR_0_OPCODE_X0) | + create_Opcode_X0(RRR_0_OPCODE_X0) | + create_UnaryOpcodeExtension_X1(NOP_UNARY_OPCODE_X1) | + create_RRROpcodeExtension_X1(UNARY_RRR_0_OPCODE_X1) | + create_Opcode_X1(RRR_0_OPCODE_X1); +} + +static inline tilegx_bundle_bits tilegx_gen_branch(unsigned long pc, + unsigned long addr, + bool link) +{ + tilegx_bundle_bits opcode_x0, opcode_x1; + long pcrel_by_instr = (addr - pc) >> TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES; + + if (link) { + /* opcode: jal addr */ + opcode_x1 = + create_Opcode_X1(JUMP_OPCODE_X1) | + create_JumpOpcodeExtension_X1(JAL_JUMP_OPCODE_X1) | + create_JumpOff_X1(pcrel_by_instr); + } else { + /* opcode: j addr */ + opcode_x1 = + create_Opcode_X1(JUMP_OPCODE_X1) | + create_JumpOpcodeExtension_X1(J_JUMP_OPCODE_X1) | + create_JumpOff_X1(pcrel_by_instr); + } + + /* opcode: fnop */ + opcode_x0 = + create_UnaryOpcodeExtension_X0(FNOP_UNARY_OPCODE_X0) | + create_RRROpcodeExtension_X0(UNARY_RRR_0_OPCODE_X0) | + create_Opcode_X0(RRR_0_OPCODE_X0); + + return opcode_x1 | opcode_x0; +} + +#endif /* __ASM_TILE_INSN_H */ diff --git a/arch/tile/include/asm/jump_label.h b/arch/tile/include/asm/jump_label.h new file mode 100644 index 0000000..cde7573 --- /dev/null +++ b/arch/tile/include/asm/jump_label.h @@ -0,0 +1,58 @@ +/* + * Copyright 2015 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ + +#ifndef _ASM_TILE_JUMP_LABEL_H +#define _ASM_TILE_JUMP_LABEL_H + +#include + +#define JUMP_LABEL_NOP_SIZE TILE_BUNDLE_SIZE_IN_BYTES + +static __always_inline bool arch_static_branch(struct static_key *key, + bool branch) +{ + asm_volatile_goto("1:\n\t" + "nop" "\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".quad 1b, %l[l_yes], %0 + %1 \n\t" + ".popsection\n\t" + : : "i" (key), "i" (branch) : : l_yes); + return false; +l_yes: + return true; +} + +static __always_inline bool arch_static_branch_jump(struct static_key *key, + bool branch) +{ + asm_volatile_goto("1:\n\t" + "j %l[l_yes]" "\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".quad 1b, %l[l_yes], %0 + %1 \n\t" + ".popsection\n\t" + : : "i" (key), "i" (branch) : : l_yes); + return false; +l_yes: + return true; +} + +typedef u64 jump_label_t; + +struct jump_entry { + jump_label_t code; + jump_label_t target; + jump_label_t key; +}; + +#endif /* _ASM_TILE_JUMP_LABEL_H */ diff --git a/arch/tile/kernel/Makefile b/arch/tile/kernel/Makefile index 21f77bf..09936d0 100644 --- a/arch/tile/kernel/Makefile +++ b/arch/tile/kernel/Makefile @@ -32,5 +32,6 @@ obj-$(CONFIG_TILE_HVGLUE_TRACE) += hvglue_trace.o obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o mcount_64.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_KGDB) += kgdb.o +obj-$(CONFIG_JUMP_LABEL) += jump_label.o obj-y += vdso/ diff --git a/arch/tile/kernel/ftrace.c b/arch/tile/kernel/ftrace.c index 4180ccdf..4a57208 100644 --- a/arch/tile/kernel/ftrace.c +++ b/arch/tile/kernel/ftrace.c @@ -20,21 +20,12 @@ #include #include #include +#include #include #ifdef CONFIG_DYNAMIC_FTRACE -static inline tilegx_bundle_bits NOP(void) -{ - return create_UnaryOpcodeExtension_X0(FNOP_UNARY_OPCODE_X0) | - create_RRROpcodeExtension_X0(UNARY_RRR_0_OPCODE_X0) | - create_Opcode_X0(RRR_0_OPCODE_X0) | - create_UnaryOpcodeExtension_X1(NOP_UNARY_OPCODE_X1) | - create_RRROpcodeExtension_X1(UNARY_RRR_0_OPCODE_X1) | - create_Opcode_X1(RRR_0_OPCODE_X1); -} - static int machine_stopped __read_mostly; int ftrace_arch_code_modify_prepare(void) diff --git a/arch/tile/kernel/jump_label.c b/arch/tile/kernel/jump_label.c new file mode 100644 index 0000000..07802d5 --- /dev/null +++ b/arch/tile/kernel/jump_label.c @@ -0,0 +1,64 @@ +/* + * Copyright 2015 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + * + * jump label TILE-Gx support + */ + +#include +#include +#include +#include +#include + +#include +#include + +#ifdef HAVE_JUMP_LABEL + +static void __jump_label_transform(struct jump_entry *e, + enum jump_label_type type) +{ + tilegx_bundle_bits opcode; + /* Operate on writable kernel text mapping. */ + unsigned long pc_wr = ktext_writable_addr(e->code); + + if (type == JUMP_LABEL_JMP) + opcode = tilegx_gen_branch(e->code, e->target, false); + else + opcode = NOP(); + + *(tilegx_bundle_bits *)pc_wr = opcode; + /* Make sure that above mem writes were issued towards the memory. */ + smp_wmb(); +} + +void arch_jump_label_transform(struct jump_entry *e, + enum jump_label_type type) +{ + get_online_cpus(); + mutex_lock(&text_mutex); + + __jump_label_transform(e, type); + flush_icache_range(e->code, e->code + sizeof(tilegx_bundle_bits)); + + mutex_unlock(&text_mutex); + put_online_cpus(); +} + +__init_or_module void arch_jump_label_transform_static(struct jump_entry *e, + enum jump_label_type type) +{ + __jump_label_transform(e, type); +} + +#endif /* HAVE_JUMP_LABEL */ -- cgit v0.10.2 From 583b24a210ada7e88fc12aaf50024975ec882816 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Tue, 22 Sep 2015 14:49:41 -0400 Subject: arch/tile: adopt prepare_exit_to_usermode() model from x86 This change is a prerequisite change for TASK_ISOLATION but also stands on its own for readability and maintainability. The existing tile do_work_pending() was called in a loop from assembly on the slow path; this change moves the loop into C code as well. For the x86 version see commit c5c46f59e4e7 ("x86/entry: Add new, comprehensible entry and exit handlers written in C"). This change exposes a pre-existing bug on the older tilepro platform; the singlestep processing is done last, but on tilepro (unlike tilegx) we enable interrupts while doing that processing, so we could in theory miss a signal or other asynchronous event. A future change could fix this by breaking the singlestep work into a "prepare" step done in the main loop, and a "trigger" step done after exiting the loop. Since this change is intended as purely a restructuring change, we call out the bug explicitly now, but don't yet fix it. Signed-off-by: Chris Metcalf diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h index 139dfde..0684e88 100644 --- a/arch/tile/include/asm/processor.h +++ b/arch/tile/include/asm/processor.h @@ -212,7 +212,7 @@ static inline void release_thread(struct task_struct *dead_task) /* Nothing for now */ } -extern int do_work_pending(struct pt_regs *regs, u32 flags); +extern void prepare_exit_to_usermode(struct pt_regs *regs, u32 flags); /* diff --git a/arch/tile/include/asm/thread_info.h b/arch/tile/include/asm/thread_info.h index dc1fb28..4b7cef9 100644 --- a/arch/tile/include/asm/thread_info.h +++ b/arch/tile/include/asm/thread_info.h @@ -140,10 +140,14 @@ extern void _cpu_idle(void); #define _TIF_POLLING_NRFLAG (1<flags. It is - * entered with interrupts disabled so we don't miss an event - * that modified the thread_info flags. If any flag is set, we - * handle it and return, and the calling assembly code will - * re-disable interrupts, reload the thread flags, and call back - * if more flags need to be handled. - * - * We return whether we need to check the thread_info flags again - * or not. Note that we don't clear TIF_SINGLESTEP here, so it's - * important that it be tested last, and then claim that we don't - * need to recheck the flags. + * TIF_ALLWORK_MASK flags are set in thread_info->flags. It is + * entered with interrupts disabled so we don't miss an event that + * modified the thread_info flags. We loop until all the tested flags + * are clear. Note that the function is called on certain conditions + * that are not listed in the loop condition here (e.g. SINGLESTEP) + * which guarantees we will do those things once, and redo them if any + * of the other work items is re-done, but won't continue looping if + * all the other work is done. */ -int do_work_pending(struct pt_regs *regs, u32 thread_info_flags) +void prepare_exit_to_usermode(struct pt_regs *regs, u32 thread_info_flags) { - /* If we enter in kernel mode, do nothing and exit the caller loop. */ - if (!user_mode(regs)) - return 0; + if (WARN_ON(!user_mode(regs))) + return; - user_exit(); + do { + local_irq_enable(); - /* Enable interrupts; they are disabled again on return to caller. */ - local_irq_enable(); + if (thread_info_flags & _TIF_NEED_RESCHED) + schedule(); - if (thread_info_flags & _TIF_NEED_RESCHED) { - schedule(); - return 1; - } #if CHIP_HAS_TILE_DMA() - if (thread_info_flags & _TIF_ASYNC_TLB) { - do_async_page_fault(regs); - return 1; - } + if (thread_info_flags & _TIF_ASYNC_TLB) + do_async_page_fault(regs); #endif - if (thread_info_flags & _TIF_SIGPENDING) { - do_signal(regs); - return 1; - } - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); - return 1; - } - if (thread_info_flags & _TIF_SINGLESTEP) + + if (thread_info_flags & _TIF_SIGPENDING) + do_signal(regs); + + if (thread_info_flags & _TIF_NOTIFY_RESUME) { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + } + + local_irq_disable(); + thread_info_flags = READ_ONCE(current_thread_info()->flags); + + } while (thread_info_flags & _TIF_WORK_MASK); + + if (thread_info_flags & _TIF_SINGLESTEP) { single_step_once(regs); +#ifndef __tilegx__ + /* + * FIXME: on tilepro, since we enable interrupts in + * this routine, it's possible that we miss a signal + * or other asynchronous event. + */ + local_irq_disable(); +#endif + } user_enter(); - - return 0; } unsigned long get_wchan(struct task_struct *p) -- cgit v0.10.2 From 7fa129ccb92c982ee8947d7fe004d7fd4f0691b9 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Fri, 18 Dec 2015 10:15:37 -0500 Subject: MAINTAINERS: add git URL for tile Signed-off-by: Fengguang Wu Signed-off-by: Chris Metcalf diff --git a/MAINTAINERS b/MAINTAINERS index 9bff63c..a905aed 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10726,6 +10726,7 @@ F: net/tipc/ TILE ARCHITECTURE M: Chris Metcalf W: http://www.ezchip.com/scm/ +T: git git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile.git S: Supported F: arch/tile/ F: drivers/char/tile-srom.c -- cgit v0.10.2 From 5ac65abd48b6d3c62ec17dc4c28830513dd605e0 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Thu, 17 Dec 2015 15:01:38 -0500 Subject: tile: include the syscall number in the backtrace This information is easily available in the backtrace data and can be helpful when trying to figure out the backtrace, particularly if we're early in kernel entry or late in kernel exit. Signed-off-by: Chris Metcalf diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c index 402b9c8..22bbbd3 100644 --- a/arch/tile/kernel/stack.c +++ b/arch/tile/kernel/stack.c @@ -78,8 +78,7 @@ static bool read_memory_func(void *result, unsigned long address, /* Return a pt_regs pointer for a valid fault handler frame */ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt) { - const char *fault = NULL; /* happy compiler */ - char fault_buf[64]; + char fault[64]; unsigned long sp = kbt->it.sp; struct pt_regs *p; @@ -90,14 +89,14 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt) if (!in_kernel_stack(kbt, sp + C_ABI_SAVE_AREA_SIZE + PTREGS_SIZE-1)) return NULL; p = (struct pt_regs *)(sp + C_ABI_SAVE_AREA_SIZE); - if (p->faultnum == INT_SWINT_1 || p->faultnum == INT_SWINT_1_SIGRETURN) - fault = "syscall"; - else { - if (kbt->verbose) { /* else we aren't going to use it */ - snprintf(fault_buf, sizeof(fault_buf), + if (kbt->verbose) { /* else we aren't going to use it */ + if (p->faultnum == INT_SWINT_1 || + p->faultnum == INT_SWINT_1_SIGRETURN) + snprintf(fault, sizeof(fault), + "syscall %ld", p->regs[TREG_SYSCALL_NR]); + else + snprintf(fault, sizeof(fault), "interrupt %ld", p->faultnum); - fault = fault_buf; - } } if (EX1_PL(p->ex1) == KERNEL_PL && __kernel_text_address(p->pc) && -- cgit v0.10.2 From f3a26163fa8f36344bf01707529052aea20368e8 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Mon, 21 Dec 2015 12:14:24 -0500 Subject: tile: fix a -Wframe-larger-than warning The warning occurs in setup.c, where it is known that it can't be a problem, but it's still a good idea to silence the warning. The onstack array is converted from an s32 to a u8, which still is plenty of range for the values being managed there. Signed-off-by: Chris Metcalf diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c index 6b755d1..bbb855d 100644 --- a/arch/tile/kernel/setup.c +++ b/arch/tile/kernel/setup.c @@ -882,7 +882,7 @@ static int __init node_neighbors(int node, int cpu, static void __init setup_numa_mapping(void) { - int distance[MAX_NUMNODES][NR_CPUS]; + u8 distance[MAX_NUMNODES][NR_CPUS]; HV_Coord coord; int cpu, node, cpus, i, x, y; int num_nodes = num_online_nodes(); -- cgit v0.10.2 From acfb699e3d757b349251ea19b8173220008d1c9e Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Mon, 21 Dec 2015 13:03:03 -0500 Subject: tile: fix tilepro casts for readl, writel, etc Missing parentheses could cause an argument of the form "integer + pointer" to get cast to "(long)integer + pointer" and remain a pointer type, causing compiler warnings. Signed-off-by: Chris Metcalf diff --git a/arch/tile/include/asm/io.h b/arch/tile/include/asm/io.h index 322b5fe..30f4a21 100644 --- a/arch/tile/include/asm/io.h +++ b/arch/tile/include/asm/io.h @@ -161,14 +161,14 @@ extern void _tile_writew(u16 val, unsigned long addr); extern void _tile_writel(u32 val, unsigned long addr); extern void _tile_writeq(u64 val, unsigned long addr); -#define __raw_readb(addr) _tile_readb((unsigned long)addr) -#define __raw_readw(addr) _tile_readw((unsigned long)addr) -#define __raw_readl(addr) _tile_readl((unsigned long)addr) -#define __raw_readq(addr) _tile_readq((unsigned long)addr) -#define __raw_writeb(val, addr) _tile_writeb(val, (unsigned long)addr) -#define __raw_writew(val, addr) _tile_writew(val, (unsigned long)addr) -#define __raw_writel(val, addr) _tile_writel(val, (unsigned long)addr) -#define __raw_writeq(val, addr) _tile_writeq(val, (unsigned long)addr) +#define __raw_readb(addr) _tile_readb((unsigned long)(addr)) +#define __raw_readw(addr) _tile_readw((unsigned long)(addr)) +#define __raw_readl(addr) _tile_readl((unsigned long)(addr)) +#define __raw_readq(addr) _tile_readq((unsigned long)(addr)) +#define __raw_writeb(val, addr) _tile_writeb(val, (unsigned long)(addr)) +#define __raw_writew(val, addr) _tile_writew(val, (unsigned long)(addr)) +#define __raw_writel(val, addr) _tile_writel(val, (unsigned long)(addr)) +#define __raw_writeq(val, addr) _tile_writeq(val, (unsigned long)(addr)) #else /* CONFIG_PCI */ -- cgit v0.10.2 From 9ce815ed50bbc518526106071f395deacaf94ad7 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Wed, 23 Dec 2015 15:02:47 -0500 Subject: tile: fix bug in setting PT_FLAGS_DISABLE_IRQ on kernel entry This flag value is saved in ptregs and used to decide whether to disable irqs when returning from the kernel. Commit 1168df528fe4 ("tile: don't assume user privilege is zero") performed a bad merge from some KVM-enabled code that had not yet been upstreamed. The only issue with the old code is that we will read the interrupt mask in more conditions than we need to (e.g., coming from user space when user space has the Interrupt Critical Section bit set, or coming from a guest kernel), which is a slow multi-cycle operation. This change saves those few cycles in the common case. Signed-off-by: Chris Metcalf diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S index a41c994..080b772 100644 --- a/arch/tile/kernel/intvec_64.S +++ b/arch/tile/kernel/intvec_64.S @@ -658,7 +658,7 @@ intvec_\vecname: */ mfspr r32, SPR_EX_CONTEXT_K_1 { - IS_KERNEL_EX1(r22, r22) + IS_KERNEL_EX1(r32, r32) PTREGS_PTR(r21, PTREGS_OFFSET_FLAGS) } beqzt r32, 1f /* zero if from user space */ -- cgit v0.10.2 From 1bb50cad45f4a3fb9a339006d76efc50f70eed5b Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Wed, 23 Dec 2015 17:13:04 -0500 Subject: arch/tile: move user_exit() to early kernel entry sequence This ensures that we always notify context tracking that we have exited from user space no matter how we enter the kernel. It is similar to how arm64 handles context tracking, for example. This allows the removal of all the exception_enter() calls that were added in commit 49e4e15619cd ("tile: support CONTEXT_TRACKING and thus NOHZ_FULL"). Signed-off-by: Chris Metcalf diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S index 33d4881..9ff75e3 100644 --- a/arch/tile/kernel/intvec_32.S +++ b/arch/tile/kernel/intvec_32.S @@ -572,7 +572,7 @@ intvec_\vecname: } wh64 r52 -#ifdef CONFIG_TRACE_IRQFLAGS +#if defined(CONFIG_TRACE_IRQFLAGS) || defined(CONFIG_CONTEXT_TRACKING) .ifnc \function,handle_nmi /* * We finally have enough state set up to notify the irq @@ -588,6 +588,9 @@ intvec_\vecname: { move r32, r2; move r33, r3 } .endif TRACE_IRQS_OFF +#ifdef CONFIG_CONTEXT_TRACKING + jal context_tracking_user_exit +#endif .ifnc \function,handle_syscall { move r0, r30; move r1, r31 } { move r2, r32; move r3, r33 } diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S index 080b772..3b51bdf 100644 --- a/arch/tile/kernel/intvec_64.S +++ b/arch/tile/kernel/intvec_64.S @@ -753,7 +753,7 @@ intvec_\vecname: } wh64 r52 -#ifdef CONFIG_TRACE_IRQFLAGS +#if defined(CONFIG_TRACE_IRQFLAGS) || defined(CONFIG_CONTEXT_TRACKING) .ifnc \function,handle_nmi /* * We finally have enough state set up to notify the irq @@ -769,6 +769,9 @@ intvec_\vecname: { move r32, r2; move r33, r3 } .endif TRACE_IRQS_OFF +#ifdef CONFIG_CONTEXT_TRACKING + jal context_tracking_user_exit +#endif .ifnc \function,handle_syscall { move r0, r30; move r1, r31 } { move r2, r32; move r3, r33 } diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c index bdc126f..54e7b72 100644 --- a/arch/tile/kernel/ptrace.c +++ b/arch/tile/kernel/ptrace.c @@ -255,13 +255,6 @@ int do_syscall_trace_enter(struct pt_regs *regs) { u32 work = ACCESS_ONCE(current_thread_info()->flags); - /* - * If TIF_NOHZ is set, we are required to call user_exit() before - * doing anything that could touch RCU. - */ - if (work & _TIF_NOHZ) - user_exit(); - if (secure_computing() == -1) return -1; @@ -281,12 +274,6 @@ void do_syscall_trace_exit(struct pt_regs *regs) long errno; /* - * We may come here right after calling schedule_user() - * in which case we can be in RCU user mode. - */ - user_exit(); - - /* * The standard tile calling convention returns the value (or negative * errno) in r0, and zero (or positive errno) in r1. * It saves a couple of cycles on the hot path to do this work in @@ -322,7 +309,5 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs) /* Handle synthetic interrupt delivered only by the simulator. */ void __kprobes do_breakpoint(struct pt_regs* regs, int fault_num) { - enum ctx_state prev_state = exception_enter(); send_sigtrap(current, regs); - exception_exit(prev_state); } diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c index 53f7b9d..8629730 100644 --- a/arch/tile/kernel/single_step.c +++ b/arch/tile/kernel/single_step.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -739,7 +738,6 @@ static DEFINE_PER_CPU(unsigned long, ss_saved_pc); void gx_singlestep_handle(struct pt_regs *regs, int fault_num) { - enum ctx_state prev_state = exception_enter(); unsigned long *ss_pc = this_cpu_ptr(&ss_saved_pc); struct thread_info *info = (void *)current_thread_info(); int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP); @@ -756,7 +754,6 @@ void gx_singlestep_handle(struct pt_regs *regs, int fault_num) __insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control); send_sigtrap(current, regs); } - exception_exit(prev_state); } diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c index 0011a9f..4d9651c 100644 --- a/arch/tile/kernel/traps.c +++ b/arch/tile/kernel/traps.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -254,7 +253,6 @@ static int do_bpt(struct pt_regs *regs) void __kprobes do_trap(struct pt_regs *regs, int fault_num, unsigned long reason) { - enum ctx_state prev_state = exception_enter(); siginfo_t info = { 0 }; int signo, code; unsigned long address = 0; @@ -263,7 +261,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, /* Handle breakpoints, etc. */ if (is_kernel && fault_num == INT_ILL && do_bpt(regs)) - goto done; + return; /* Re-enable interrupts, if they were previously enabled. */ if (!(regs->flags & PT_FLAGS_DISABLE_IRQ)) @@ -277,7 +275,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, const char *name; char buf[100]; if (fixup_exception(regs)) /* ILL_TRANS or UNALIGN_DATA */ - goto done; + return; if (fault_num >= 0 && fault_num < ARRAY_SIZE(int_name) && int_name[fault_num] != NULL) @@ -319,7 +317,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, case INT_GPV: #if CHIP_HAS_TILE_DMA() if (retry_gpv(reason)) - goto done; + return; #endif /*FALLTHROUGH*/ case INT_UDN_ACCESS: @@ -346,7 +344,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, if (!state || (void __user *)(regs->pc) != state->buffer) { single_step_once(regs); - goto done; + return; } } #endif @@ -390,9 +388,6 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, if (signo != SIGTRAP) trace_unhandled_signal("trap", regs, address, signo); force_sig_info(signo, &info, current); - -done: - exception_exit(prev_state); } void do_nmi(struct pt_regs *regs, int fault_num, unsigned long reason) diff --git a/arch/tile/kernel/unaligned.c b/arch/tile/kernel/unaligned.c index d075f92..0db5f7c 100644 --- a/arch/tile/kernel/unaligned.c +++ b/arch/tile/kernel/unaligned.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -1449,7 +1448,6 @@ void jit_bundle_gen(struct pt_regs *regs, tilegx_bundle_bits bundle, void do_unaligned(struct pt_regs *regs, int vecnum) { - enum ctx_state prev_state = exception_enter(); tilegx_bundle_bits __user *pc; tilegx_bundle_bits bundle; struct thread_info *info = current_thread_info(); @@ -1503,7 +1501,7 @@ void do_unaligned(struct pt_regs *regs, int vecnum) *((tilegx_bundle_bits *)(regs->pc))); jit_bundle_gen(regs, bundle, align_ctl); } - goto done; + return; } /* @@ -1527,7 +1525,7 @@ void do_unaligned(struct pt_regs *regs, int vecnum) trace_unhandled_signal("unaligned fixup trap", regs, 0, SIGBUS); force_sig_info(info.si_signo, &info, current); - goto done; + return; } @@ -1544,7 +1542,7 @@ void do_unaligned(struct pt_regs *regs, int vecnum) trace_unhandled_signal("segfault in unalign fixup", regs, (unsigned long)info.si_addr, SIGSEGV); force_sig_info(info.si_signo, &info, current); - goto done; + return; } if (!info->unalign_jit_base) { @@ -1579,7 +1577,7 @@ void do_unaligned(struct pt_regs *regs, int vecnum) if (IS_ERR((void __force *)user_page)) { pr_err("Out of kernel pages trying do_mmap\n"); - goto done; + return; } /* Save the address in the thread_info struct */ @@ -1592,9 +1590,6 @@ void do_unaligned(struct pt_regs *regs, int vecnum) /* Generate unalign JIT */ jit_bundle_gen(regs, GX_INSN_BSWAP(bundle), align_ctl); - -done: - exception_exit(prev_state); } #endif /* __tilegx__ */ diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c index 13eac59..2673421 100644 --- a/arch/tile/mm/fault.c +++ b/arch/tile/mm/fault.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -845,9 +844,7 @@ static inline void __do_page_fault(struct pt_regs *regs, int fault_num, void do_page_fault(struct pt_regs *regs, int fault_num, unsigned long address, unsigned long write) { - enum ctx_state prev_state = exception_enter(); __do_page_fault(regs, fault_num, address, write); - exception_exit(prev_state); } #if CHIP_HAS_TILE_DMA() -- cgit v0.10.2 From 00d27c6336b00345724b2510f7c5b8cee3055f02 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Tue, 5 Jan 2016 11:22:10 -0500 Subject: numa: remove stale node_has_online_mem() define This isn't used anywhere, so delete it. Looks like the last usage (in x86-specific code) was removed by Tejun in 2011 in commit bd6709a91a59 ("x86, NUMA: Make 32bit use common NUMA init path"). Signed-off-by: Chris Metcalf diff --git a/arch/tile/include/asm/topology.h b/arch/tile/include/asm/topology.h index 76b0d0e..b11d5fc 100644 --- a/arch/tile/include/asm/topology.h +++ b/arch/tile/include/asm/topology.h @@ -44,9 +44,6 @@ static inline const struct cpumask *cpumask_of_node(int node) /* For now, use numa node -1 for global allocation. */ #define pcibus_to_node(bus) ((void)(bus), -1) -/* By definition, we create nodes based on online memory. */ -#define node_has_online_mem(nid) 1 - #endif /* CONFIG_NUMA */ #include diff --git a/include/linux/topology.h b/include/linux/topology.h index 73ddad1..afce692 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -34,10 +34,6 @@ #include #include -#ifndef node_has_online_mem -#define node_has_online_mem(nid) (1) -#endif - #ifndef nr_cpus_node #define nr_cpus_node(node) cpumask_weight(cpumask_of_node(node)) #endif -- cgit v0.10.2