Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tile: support GENERIC_KERNEL_THREAD and GENERIC_KERNEL_EXECVE

Also provide an optimized current_pt_regs() while we're at it.

Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

authored by

Chris Metcalf and committed by
Al Viro
0f8b9838 733deca1

+75 -76
+2
arch/tile/Kconfig
··· 21 21 select ARCH_HAVE_NMI_SAFE_CMPXCHG 22 22 select GENERIC_CLOCKEVENTS 23 23 select MODULES_USE_ELF_RELA 24 + select GENERIC_KERNEL_THREAD 25 + select GENERIC_KERNEL_EXECVE 24 26 25 27 # FIXME: investigate whether we need/want these options. 26 28 # select HAVE_IOREMAP_PROT
+4 -1
arch/tile/include/asm/switch_to.h
··· 68 68 /* Support function for forking a new task. */ 69 69 void ret_from_fork(void); 70 70 71 - /* Called from ret_from_fork() when a new process starts up. */ 71 + /* Support function for forking a new kernel thread. */ 72 + void ret_from_kernel_thread(void *fn, void *arg); 73 + 74 + /* Called from ret_from_xxx() when a new process starts up. */ 72 75 struct task_struct *sim_notify_fork(struct task_struct *prev); 73 76 74 77 #endif /* !__ASSEMBLY__ */
-11
arch/tile/kernel/entry.S
··· 28 28 STD_ENDPROC(current_text_addr) 29 29 30 30 /* 31 - * Implement execve(). The i386 code has a note that forking from kernel 32 - * space results in no copy on write until the execve, so we should be 33 - * careful not to write to the stack here. 34 - */ 35 - STD_ENTRY(kernel_execve) 36 - moveli TREG_SYSCALL_NR_NAME, __NR_execve 37 - swint1 38 - jrp lr 39 - STD_ENDPROC(kernel_execve) 40 - 41 - /* 42 31 * We don't run this function directly, but instead copy it to a page 43 32 * we map into every user process. See vdso_setup(). 44 33 *
+15
arch/tile/kernel/intvec_32.S
··· 1291 1291 } 1292 1292 STD_ENDPROC(ret_from_fork) 1293 1293 1294 + STD_ENTRY(ret_from_kernel_thread) 1295 + jal sim_notify_fork 1296 + jal schedule_tail 1297 + FEEDBACK_REENTER(ret_from_fork) 1298 + { 1299 + move r0, r31 1300 + jalr r30 1301 + } 1302 + FEEDBACK_REENTER(ret_from_kernel_thread) 1303 + { 1304 + movei r30, 0 /* not an NMI */ 1305 + j .Lresume_userspace /* jump into middle of interrupt_return */ 1306 + } 1307 + STD_ENDPROC(ret_from_kernel_thread) 1308 + 1294 1309 /* 1295 1310 * Code for ill interrupt. 1296 1311 */
+15
arch/tile/kernel/intvec_64.S
··· 1150 1150 } 1151 1151 STD_ENDPROC(ret_from_fork) 1152 1152 1153 + STD_ENTRY(ret_from_kernel_thread) 1154 + jal sim_notify_fork 1155 + jal schedule_tail 1156 + FEEDBACK_REENTER(ret_from_fork) 1157 + { 1158 + move r0, r31 1159 + jalr r30 1160 + } 1161 + FEEDBACK_REENTER(ret_from_kernel_thread) 1162 + { 1163 + movei r30, 0 /* not an NMI */ 1164 + j .Lresume_userspace /* jump into middle of interrupt_return */ 1165 + } 1166 + STD_ENDPROC(ret_from_kernel_thread) 1167 + 1153 1168 /* Various stub interrupt handlers and syscall handlers */ 1154 1169 1155 1170 STD_ENTRY_LOCAL(_kernel_double_fault)
+39 -64
arch/tile/kernel/process.c
··· 157 157 static void save_arch_state(struct thread_struct *t); 158 158 159 159 int copy_thread(unsigned long clone_flags, unsigned long sp, 160 - unsigned long stack_size, 160 + unsigned long arg, 161 161 struct task_struct *p, struct pt_regs *regs) 162 162 { 163 - struct pt_regs *childregs; 163 + struct pt_regs *childregs = task_pt_regs(p); 164 164 unsigned long ksp; 165 + unsigned long *callee_regs; 165 166 166 167 /* 167 - * When creating a new kernel thread we pass sp as zero. 168 - * Assign it to a reasonable value now that we have the stack. 168 + * Set up the stack and stack pointer appropriately for the 169 + * new child to find itself woken up in __switch_to(). 170 + * The callee-saved registers must be on the stack to be read; 171 + * the new task will then jump to assembly support to handle 172 + * calling schedule_tail(), etc., and (for userspace tasks) 173 + * returning to the context set up in the pt_regs. 169 174 */ 170 - if (sp == 0 && regs->ex1 == PL_ICS_EX1(KERNEL_PL, 0)) 171 - sp = KSTK_TOP(p); 175 + ksp = (unsigned long) childregs; 176 + ksp -= C_ABI_SAVE_AREA_SIZE; /* interrupt-entry save area */ 177 + ((long *)ksp)[0] = ((long *)ksp)[1] = 0; 178 + ksp -= CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long); 179 + callee_regs = (unsigned long *)ksp; 180 + ksp -= C_ABI_SAVE_AREA_SIZE; /* __switch_to() save area */ 181 + ((long *)ksp)[0] = ((long *)ksp)[1] = 0; 182 + p->thread.ksp = ksp; 172 183 173 - /* 174 - * Do not clone step state from the parent; each thread 175 - * must make its own lazily. 176 - */ 177 - task_thread_info(p)->step_state = NULL; 184 + /* Record the pid of the task that created this one. */ 185 + p->thread.creator_pid = current->pid; 186 + 187 + if (unlikely(!regs)) { 188 + /* kernel thread */ 189 + memset(childregs, 0, sizeof(struct pt_regs)); 190 + memset(&callee_regs[2], 0, 191 + (CALLEE_SAVED_REGS_COUNT - 2) * sizeof(unsigned long)); 192 + callee_regs[0] = sp; /* r30 = function */ 193 + callee_regs[1] = arg; /* r31 = arg */ 194 + childregs->ex1 = PL_ICS_EX1(KERNEL_PL, 0); 195 + p->thread.pc = (unsigned long) ret_from_kernel_thread; 196 + return 0; 197 + } 178 198 179 199 /* 180 200 * Start new thread in ret_from_fork so it schedules properly ··· 202 182 */ 203 183 p->thread.pc = (unsigned long) ret_from_fork; 204 184 185 + /* 186 + * Do not clone step state from the parent; each thread 187 + * must make its own lazily. 188 + */ 189 + task_thread_info(p)->step_state = NULL; 190 + 205 191 /* Save user stack top pointer so we can ID the stack vm area later. */ 206 192 p->thread.usp0 = sp; 207 - 208 - /* Record the pid of the process that created this one. */ 209 - p->thread.creator_pid = current->pid; 210 193 211 194 /* 212 195 * Copy the registers onto the kernel stack so the 213 196 * return-from-interrupt code will reload it into registers. 214 197 */ 215 - childregs = task_pt_regs(p); 216 198 *childregs = *regs; 217 199 childregs->regs[0] = 0; /* return value is zero */ 218 200 childregs->sp = sp; /* override with new user stack pointer */ 201 + memcpy(callee_regs, &regs->regs[CALLEE_SAVED_FIRST_REG], 202 + CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long)); 219 203 220 204 /* 221 205 * If CLONE_SETTLS is set, set "tp" in the new task to "r4", ··· 228 204 if (clone_flags & CLONE_SETTLS) 229 205 childregs->tp = regs->regs[4]; 230 206 231 - /* 232 - * Copy the callee-saved registers from the passed pt_regs struct 233 - * into the context-switch callee-saved registers area. 234 - * This way when we start the interrupt-return sequence, the 235 - * callee-save registers will be correctly in registers, which 236 - * is how we assume the compiler leaves them as we start doing 237 - * the normal return-from-interrupt path after calling C code. 238 - * Zero out the C ABI save area to mark the top of the stack. 239 - */ 240 - ksp = (unsigned long) childregs; 241 - ksp -= C_ABI_SAVE_AREA_SIZE; /* interrupt-entry save area */ 242 - ((long *)ksp)[0] = ((long *)ksp)[1] = 0; 243 - ksp -= CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long); 244 - memcpy((void *)ksp, &regs->regs[CALLEE_SAVED_FIRST_REG], 245 - CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long)); 246 - ksp -= C_ABI_SAVE_AREA_SIZE; /* __switch_to() save area */ 247 - ((long *)ksp)[0] = ((long *)ksp)[1] = 0; 248 - p->thread.ksp = ksp; 249 207 250 208 #if CHIP_HAS_TILE_DMA() 251 209 /* ··· 655 649 656 650 return 0; 657 651 } 658 - 659 - /* 660 - * We pass in lr as zero (cleared in kernel_thread) and the caller 661 - * part of the backtrace ABI on the stack also zeroed (in copy_thread) 662 - * so that backtraces will stop with this function. 663 - * Note that we don't use r0, since copy_thread() clears it. 664 - */ 665 - static void start_kernel_thread(int dummy, int (*fn)(int), int arg) 666 - { 667 - do_exit(fn(arg)); 668 - } 669 - 670 - /* 671 - * Create a kernel thread 672 - */ 673 - int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) 674 - { 675 - struct pt_regs regs; 676 - 677 - memset(&regs, 0, sizeof(regs)); 678 - regs.ex1 = PL_ICS_EX1(KERNEL_PL, 0); /* run at kernel PL, no ICS */ 679 - regs.pc = (long) start_kernel_thread; 680 - regs.flags = PT_FLAGS_CALLER_SAVES; /* need to restore r1 and r2 */ 681 - regs.regs[1] = (long) fn; /* function pointer */ 682 - regs.regs[2] = (long) arg; /* parameter register */ 683 - 684 - /* Ok, create the new process.. */ 685 - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 686 - 0, NULL, NULL); 687 - } 688 - EXPORT_SYMBOL(kernel_thread); 689 652 690 653 /* Flush thread state. */ 691 654 void flush_thread(void)