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

ARC: Process-creation/scheduling/idle-loop

Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>

+484 -8
+2
arch/arc/Kconfig
··· 17 17 select GENERIC_FIND_FIRST_BIT 18 18 # for now, we don't need GENERIC_IRQ_PROBE, CONFIG_GENERIC_IRQ_CHIP 19 19 select GENERIC_IRQ_SHOW 20 + select GENERIC_KERNEL_EXECVE 21 + select GENERIC_KERNEL_THREAD 20 22 select GENERIC_PENDING_IRQ if SMP 21 23 select GENERIC_SMP_IDLE_THREAD 22 24 select HAVE_GENERIC_HARDIRQS
+20
arch/arc/include/asm/arcregs.h
··· 47 47 #define AUX_ITRIGGER 0x40d 48 48 #define AUX_IPULSE 0x415 49 49 50 + /* 51 + * Floating Pt Registers 52 + * Status regs are read-only (build-time) so need not be saved/restored 53 + */ 54 + #define ARC_AUX_FP_STAT 0x300 55 + #define ARC_AUX_DPFP_1L 0x301 56 + #define ARC_AUX_DPFP_1H 0x302 57 + #define ARC_AUX_DPFP_2L 0x303 58 + #define ARC_AUX_DPFP_2H 0x304 59 + #define ARC_AUX_DPFP_STAT 0x305 60 + 50 61 #ifndef __ASSEMBLY__ 51 62 52 63 /* ··· 119 108 : "r"(val), "memory"(&reg_in_var)); \ 120 109 }) 121 110 111 + #endif 112 + 113 + #ifdef CONFIG_ARC_FPU_SAVE_RESTORE 114 + /* These DPFP regs need to be saved/restored across ctx-sw */ 115 + struct arc_fpu { 116 + struct { 117 + unsigned int l, h; 118 + } aux_dpfp[2]; 119 + }; 122 120 #endif 123 121 124 122 #endif /* __ASEMBLY__ */
+3 -6
arch/arc/include/asm/processor.h
··· 29 29 unsigned long callee_reg; /* pointer to callee regs */ 30 30 unsigned long fault_address; /* dbls as brkpt holder as well */ 31 31 unsigned long cause_code; /* Exception Cause Code (ECR) */ 32 + #ifdef CONFIG_ARC_FPU_SAVE_RESTORE 33 + struct arc_fpu fpu; 34 + #endif 32 35 }; 33 36 34 37 #define INIT_THREAD { \ ··· 56 53 #define prepare_to_copy(tsk) do { } while (0) 57 54 58 55 #define cpu_relax() do { } while (0) 59 - 60 - /* 61 - * Create a new kernel thread 62 - */ 63 - 64 - extern int kernel_thread(int (*fn) (void *), void *arg, unsigned long flags); 65 56 66 57 #define copy_segments(tsk, mm) do { } while (0) 67 58 #define release_segments(mm) do { } while (0)
+8
arch/arc/include/asm/ptrace.h
··· 91 91 #define in_syscall(regs) (((regs->orig_r8) >= 0 && \ 92 92 (regs->orig_r8 <= NR_syscalls)) ? 1 : 0) 93 93 94 + #define current_pt_regs() \ 95 + ({ \ 96 + /* open-coded current_thread_info() */ \ 97 + register unsigned long sp asm ("sp"); \ 98 + unsigned long pg_start = (sp & ~(THREAD_SIZE - 1)); \ 99 + (struct pt_regs *)(pg_start + THREAD_SIZE - 4) - 1; \ 100 + }) 101 + 94 102 #endif /* !__ASSEMBLY__ */ 95 103 96 104 #endif /* __KERNEL__ */
+41
arch/arc/include/asm/switch_to.h
··· 1 + /* 2 + * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #ifndef _ASM_ARC_SWITCH_TO_H 10 + #define _ASM_ARC_SWITCH_TO_H 11 + 12 + #ifndef __ASSEMBLY__ 13 + 14 + #include <linux/sched.h> 15 + 16 + #ifdef CONFIG_ARC_FPU_SAVE_RESTORE 17 + 18 + extern void fpu_save_restore(struct task_struct *p, struct task_struct *n); 19 + #define ARC_FPU_PREV(p, n) fpu_save_restore(p, n) 20 + #define ARC_FPU_NEXT(t) 21 + 22 + #else 23 + 24 + #define ARC_FPU_PREV(p, n) 25 + #define ARC_FPU_NEXT(n) 26 + 27 + #endif /* !CONFIG_ARC_FPU_SAVE_RESTORE */ 28 + 29 + struct task_struct *__switch_to(struct task_struct *p, struct task_struct *n); 30 + 31 + #define switch_to(prev, next, last) \ 32 + do { \ 33 + ARC_FPU_PREV(prev, next); \ 34 + last = __switch_to(prev, next);\ 35 + ARC_FPU_NEXT(next); \ 36 + mb(); \ 37 + } while (0) 38 + 39 + #endif 40 + 41 + #endif
+91
arch/arc/kernel/ctx_sw.c
··· 1 + /* 2 + * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * Vineetg: Aug 2009 9 + * -"C" version of lowest level context switch asm macro called by schedular 10 + * gcc doesn't generate the dward CFI info for hand written asm, hence can't 11 + * backtrace out of it (e.g. tasks sleeping in kernel). 12 + * So we cheat a bit by writing almost similar code in inline-asm. 13 + * -This is a hacky way of doing things, but there is no other simple way. 14 + * I don't want/intend to extend unwinding code to understand raw asm 15 + */ 16 + 17 + #include <asm/asm-offsets.h> 18 + #include <linux/sched.h> 19 + 20 + struct task_struct *__sched 21 + __switch_to(struct task_struct *prev_task, struct task_struct *next_task) 22 + { 23 + unsigned int tmp; 24 + unsigned int prev = (unsigned int)prev_task; 25 + unsigned int next = (unsigned int)next_task; 26 + int num_words_to_skip = 1; 27 + 28 + __asm__ __volatile__( 29 + /* FP/BLINK save generated by gcc (standard function prologue */ 30 + "st.a r13, [sp, -4] \n\t" 31 + "st.a r14, [sp, -4] \n\t" 32 + "st.a r15, [sp, -4] \n\t" 33 + "st.a r16, [sp, -4] \n\t" 34 + "st.a r17, [sp, -4] \n\t" 35 + "st.a r18, [sp, -4] \n\t" 36 + "st.a r19, [sp, -4] \n\t" 37 + "st.a r20, [sp, -4] \n\t" 38 + "st.a r21, [sp, -4] \n\t" 39 + "st.a r22, [sp, -4] \n\t" 40 + "st.a r23, [sp, -4] \n\t" 41 + "st.a r24, [sp, -4] \n\t" 42 + "st.a r25, [sp, -4] \n\t" 43 + "sub sp, sp, %4 \n\t" /* create gutter at top */ 44 + 45 + /* set ksp of outgoing task in tsk->thread.ksp */ 46 + "st.as sp, [%3, %1] \n\t" 47 + 48 + "sync \n\t" 49 + 50 + /* 51 + * setup _current_task with incoming tsk. 52 + * optionally, set r25 to that as well 53 + * For SMP extra work to get to &_current_task[cpu] 54 + * (open coded SET_CURR_TASK_ON_CPU) 55 + */ 56 + "st %2, [@_current_task] \n\t" 57 + 58 + /* get ksp of incoming task from tsk->thread.ksp */ 59 + "ld.as sp, [%2, %1] \n\t" 60 + 61 + /* start loading it's CALLEE reg file */ 62 + 63 + "add sp, sp, %4 \n\t" /* skip gutter at top */ 64 + 65 + "ld.ab r25, [sp, 4] \n\t" 66 + "ld.ab r24, [sp, 4] \n\t" 67 + "ld.ab r23, [sp, 4] \n\t" 68 + "ld.ab r22, [sp, 4] \n\t" 69 + "ld.ab r21, [sp, 4] \n\t" 70 + "ld.ab r20, [sp, 4] \n\t" 71 + "ld.ab r19, [sp, 4] \n\t" 72 + "ld.ab r18, [sp, 4] \n\t" 73 + "ld.ab r17, [sp, 4] \n\t" 74 + "ld.ab r16, [sp, 4] \n\t" 75 + "ld.ab r15, [sp, 4] \n\t" 76 + "ld.ab r14, [sp, 4] \n\t" 77 + "ld.ab r13, [sp, 4] \n\t" 78 + 79 + /* last (ret value) = prev : although for ARC it mov r0, r0 */ 80 + "mov %0, %3 \n\t" 81 + 82 + /* FP/BLINK restore generated by gcc (standard func epilogue */ 83 + 84 + : "=r"(tmp) 85 + : "n"((TASK_THREAD + THREAD_KSP) / 4), "r"(next), "r"(prev), 86 + "n"(num_words_to_skip * 4) 87 + : "blink" 88 + ); 89 + 90 + return (struct task_struct *)tmp; 91 + }
+58
arch/arc/kernel/ctx_sw_asm.S
··· 1 + /* 2 + * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * Vineetg: Aug 2009 9 + * -Moved core context switch macro out of entry.S into this file. 10 + * -This is the more "natural" hand written assembler 11 + */ 12 + 13 + #include <asm/entry.h> /* For the SAVE_* macros */ 14 + #include <asm/asm-offsets.h> 15 + #include <asm/linkage.h> 16 + 17 + ;################### Low Level Context Switch ########################## 18 + 19 + .section .sched.text,"ax",@progbits 20 + .align 4 21 + .global __switch_to 22 + .type __switch_to, @function 23 + __switch_to: 24 + 25 + /* Save regs on kernel mode stack of task */ 26 + st.a blink, [sp, -4] 27 + st.a fp, [sp, -4] 28 + SAVE_CALLEE_SAVED_KERNEL 29 + 30 + /* Save the now KSP in task->thread.ksp */ 31 + st.as sp, [r0, (TASK_THREAD + THREAD_KSP)/4] 32 + 33 + /* 34 + * Return last task in r0 (return reg) 35 + * On ARC, Return reg = First Arg reg = r0. 36 + * Since we already have last task in r0, 37 + * don't need to do anything special to return it 38 + */ 39 + 40 + /* hardware memory barrier */ 41 + sync 42 + 43 + /* 44 + * switch to new task, contained in r1 45 + * Temp reg r3 is required to get the ptr to store val 46 + */ 47 + SET_CURR_TASK_ON_CPU r1, r3 48 + 49 + /* reload SP with kernel mode stack pointer in task->thread.ksp */ 50 + ld.as sp, [r1, (TASK_THREAD + THREAD_KSP)/4] 51 + 52 + /* restore the registers */ 53 + RESTORE_CALLEE_SAVED_KERNEL 54 + ld.ab fp, [sp, 4] 55 + ld.ab blink, [sp, 4] 56 + j [blink] 57 + 58 + ARC_EXIT __switch_to
+13 -2
arch/arc/kernel/entry.S
··· 566 566 ; when the forked child comes here from the __switch_to function 567 567 ; r0 has the last task pointer. 568 568 ; put last task in scheduler queue 569 - bl @schedule_tail 570 - b @ret_from_exception 569 + bl @schedule_tail 570 + 571 + ; If kernel thread, jump to it's entry-point 572 + ld r9, [sp, PT_status32] 573 + brne r9, 0, 1f 574 + 575 + jl.d [r14] 576 + mov r0, r13 ; arg to payload 577 + 578 + 1: 579 + ; special case of kernel_thread entry point returning back due to 580 + ; kernel_execve() - pretend return from syscall to ret to userland 581 + b ret_from_exception 571 582 ARC_EXIT ret_from_fork 572 583 573 584 ;################### Special Sys Call Wrappers ##########################
+55
arch/arc/kernel/fpu.c
··· 1 + /* 2 + * fpu.c - save/restore of Floating Point Unit Registers on task switch 3 + * 4 + * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + */ 10 + 11 + #include <linux/sched.h> 12 + #include <asm/switch_to.h> 13 + 14 + /* 15 + * To save/restore FPU regs, simplest scheme would use LR/SR insns. 16 + * However since SR serializes the pipeline, an alternate "hack" can be used 17 + * which uses the FPU Exchange insn (DEXCL) to r/w FPU regs. 18 + * 19 + * Store to 64bit dpfp1 reg from a pair of core regs: 20 + * dexcl1 0, r1, r0 ; where r1:r0 is the 64 bit val 21 + * 22 + * Read from dpfp1 into pair of core regs (w/o clobbering dpfp1) 23 + * mov_s r3, 0 24 + * daddh11 r1, r3, r3 ; get "hi" into r1 (dpfp1 unchanged) 25 + * dexcl1 r0, r1, r3 ; get "low" into r0 (dpfp1 low clobbered) 26 + * dexcl1 0, r1, r0 ; restore dpfp1 to orig value 27 + * 28 + * However we can tweak the read, so that read-out of outgoing task's FPU regs 29 + * and write of incoming task's regs happen in one shot. So all the work is 30 + * done before context switch 31 + */ 32 + 33 + void fpu_save_restore(struct task_struct *prev, struct task_struct *next) 34 + { 35 + unsigned int *saveto = &prev->thread.fpu.aux_dpfp[0].l; 36 + unsigned int *readfrom = &next->thread.fpu.aux_dpfp[0].l; 37 + 38 + const unsigned int zero = 0; 39 + 40 + __asm__ __volatile__( 41 + "daddh11 %0, %2, %2\n" 42 + "dexcl1 %1, %3, %4\n" 43 + : "=&r" (*(saveto + 1)), /* early clobber must here */ 44 + "=&r" (*(saveto)) 45 + : "r" (zero), "r" (*(readfrom + 1)), "r" (*(readfrom)) 46 + ); 47 + 48 + __asm__ __volatile__( 49 + "daddh22 %0, %2, %2\n" 50 + "dexcl2 %1, %3, %4\n" 51 + : "=&r"(*(saveto + 3)), /* early clobber must here */ 52 + "=&r"(*(saveto + 2)) 53 + : "r" (zero), "r" (*(readfrom + 3)), "r" (*(readfrom + 2)) 54 + ); 55 + }
+193
arch/arc/kernel/process.c
··· 40 40 { 41 41 return task_thread_info(current)->thr_ptr; 42 42 } 43 + 44 + static inline void arch_idle(void) 45 + { 46 + /* sleep, but enable all interrupts before committing */ 47 + __asm__("sleep 0x3"); 48 + } 49 + 50 + void cpu_idle(void) 51 + { 52 + /* Since we SLEEP in idle loop, TIF_POLLING_NRFLAG can't be set */ 53 + 54 + /* endless idle loop with no priority at all */ 55 + while (1) { 56 + tick_nohz_idle_enter(); 57 + rcu_idle_enter(); 58 + 59 + doze: 60 + local_irq_disable(); 61 + if (!need_resched()) { 62 + arch_idle(); 63 + goto doze; 64 + } else { 65 + local_irq_enable(); 66 + } 67 + 68 + rcu_idle_exit(); 69 + tick_nohz_idle_exit(); 70 + 71 + schedule_preempt_disabled(); 72 + } 73 + } 74 + 75 + asmlinkage void ret_from_fork(void); 76 + 77 + /* Layout of Child kernel mode stack as setup at the end of this function is 78 + * 79 + * | ... | 80 + * | ... | 81 + * | unused | 82 + * | | 83 + * ------------------ <==== top of Stack (thread.ksp) 84 + * | UNUSED 1 word| 85 + * ------------------ 86 + * | r25 | 87 + * ~ ~ 88 + * | --to-- | (CALLEE Regs of user mode) 89 + * | r13 | 90 + * ------------------ 91 + * | fp | 92 + * | blink | @ret_from_fork 93 + * ------------------ 94 + * | | 95 + * ~ ~ 96 + * ~ ~ 97 + * | | 98 + * ------------------ 99 + * | r12 | 100 + * ~ ~ 101 + * | --to-- | (scratch Regs of user mode) 102 + * | r0 | 103 + * ------------------ 104 + * | UNUSED 1 word| 105 + * ------------------ <===== END of PAGE 106 + */ 107 + int copy_thread(unsigned long clone_flags, 108 + unsigned long usp, unsigned long arg, 109 + struct task_struct *p) 110 + { 111 + struct pt_regs *c_regs; /* child's pt_regs */ 112 + unsigned long *childksp; /* to unwind out of __switch_to() */ 113 + struct callee_regs *c_callee; /* child's callee regs */ 114 + struct callee_regs *parent_callee; /* paren't callee */ 115 + struct pt_regs *regs = current_pt_regs(); 116 + 117 + /* Mark the specific anchors to begin with (see pic above) */ 118 + c_regs = task_pt_regs(p); 119 + childksp = (unsigned long *)c_regs - 2; /* 2 words for FP/BLINK */ 120 + c_callee = ((struct callee_regs *)childksp) - 1; 121 + 122 + /* 123 + * __switch_to() uses thread.ksp to start unwinding stack 124 + * For kernel threads we don't need to create callee regs, the 125 + * stack layout nevertheless needs to remain the same. 126 + * Also, since __switch_to anyways unwinds callee regs, we use 127 + * this to populate kernel thread entry-pt/args into callee regs, 128 + * so that ret_from_kernel_thread() becomes simpler. 129 + */ 130 + p->thread.ksp = (unsigned long)c_callee; /* THREAD_KSP */ 131 + 132 + /* __switch_to expects FP(0), BLINK(return addr) at top */ 133 + childksp[0] = 0; /* fp */ 134 + childksp[1] = (unsigned long)ret_from_fork; /* blink */ 135 + 136 + if (unlikely(p->flags & PF_KTHREAD)) { 137 + memset(c_regs, 0, sizeof(struct pt_regs)); 138 + 139 + c_callee->r13 = arg; /* argument to kernel thread */ 140 + c_callee->r14 = usp; /* function */ 141 + 142 + return 0; 143 + } 144 + 145 + /*--------- User Task Only --------------*/ 146 + 147 + /* __switch_to expects FP(0), BLINK(return addr) at top of stack */ 148 + childksp[0] = 0; /* for POP fp */ 149 + childksp[1] = (unsigned long)ret_from_fork; /* for POP blink */ 150 + 151 + /* Copy parents pt regs on child's kernel mode stack */ 152 + *c_regs = *regs; 153 + 154 + if (usp) 155 + c_regs->sp = usp; 156 + 157 + c_regs->r0 = 0; /* fork returns 0 in child */ 158 + 159 + parent_callee = ((struct callee_regs *)regs) - 1; 160 + *c_callee = *parent_callee; 161 + 162 + if (unlikely(clone_flags & CLONE_SETTLS)) { 163 + /* 164 + * set task's userland tls data ptr from 4th arg 165 + * clone C-lib call is difft from clone sys-call 166 + */ 167 + task_thread_info(p)->thr_ptr = regs->r3; 168 + } else { 169 + /* Normal fork case: set parent's TLS ptr in child */ 170 + task_thread_info(p)->thr_ptr = 171 + task_thread_info(current)->thr_ptr; 172 + } 173 + 174 + return 0; 175 + } 176 + 177 + /* 178 + * Some archs flush debug and FPU info here 179 + */ 180 + void flush_thread(void) 181 + { 182 + } 183 + 184 + /* 185 + * Free any architecture-specific thread data structures, etc. 186 + */ 187 + void exit_thread(void) 188 + { 189 + } 190 + 191 + int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) 192 + { 193 + return 0; 194 + } 195 + 196 + /* 197 + * API: expected by schedular Code: If thread is sleeping where is that. 198 + * What is this good for? it will be always the scheduler or ret_from_fork. 199 + * So we hard code that anyways. 200 + */ 201 + unsigned long thread_saved_pc(struct task_struct *t) 202 + { 203 + struct pt_regs *regs = task_pt_regs(t); 204 + unsigned long blink = 0; 205 + 206 + /* 207 + * If the thread being queried for in not itself calling this, then it 208 + * implies it is not executing, which in turn implies it is sleeping, 209 + * which in turn implies it got switched OUT by the schedular. 210 + * In that case, it's kernel mode blink can reliably retrieved as per 211 + * the picture above (right above pt_regs). 212 + */ 213 + if (t != current && t->state != TASK_RUNNING) 214 + blink = *((unsigned int *)regs - 1); 215 + 216 + return blink; 217 + } 218 + 219 + int elf_check_arch(const struct elf32_hdr *x) 220 + { 221 + unsigned int eflags; 222 + 223 + if (x->e_machine != EM_ARCOMPACT) 224 + return 0; 225 + 226 + eflags = x->e_flags; 227 + if ((eflags & EF_ARC_OSABI_MSK) < EF_ARC_OSABI_V2) { 228 + pr_err("ABI mismatch - you need newer toolchain\n"); 229 + force_sigsegv(SIGSEGV, current); 230 + return 0; 231 + } 232 + 233 + return 1; 234 + } 235 + EXPORT_SYMBOL(elf_check_arch);