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

unicore32 core architecture: process/thread related codes

This patch implements process/thread related codes. Backtrace and stacktrace are here.

Signed-off-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>

+912
+31
arch/unicore32/include/asm/stacktrace.h
··· 1 + /* 2 + * linux/arch/unicore32/include/asm/stacktrace.h 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + 13 + #ifndef __UNICORE_STACKTRACE_H__ 14 + #define __UNICORE_STACKTRACE_H__ 15 + 16 + struct stackframe { 17 + unsigned long fp; 18 + unsigned long sp; 19 + unsigned long lr; 20 + unsigned long pc; 21 + }; 22 + 23 + #ifdef CONFIG_FRAME_POINTER 24 + extern int unwind_frame(struct stackframe *frame); 25 + #else 26 + #define unwind_frame(f) (-EINVAL) 27 + #endif 28 + extern void walk_stackframe(struct stackframe *frame, 29 + int (*fn)(struct stackframe *, void *), void *data); 30 + 31 + #endif /* __UNICORE_STACKTRACE_H__ */
+154
arch/unicore32/include/asm/thread_info.h
··· 1 + /* 2 + * linux/arch/unicore32/include/asm/thread_info.h 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + #ifndef __UNICORE_THREAD_INFO_H__ 13 + #define __UNICORE_THREAD_INFO_H__ 14 + 15 + #ifdef __KERNEL__ 16 + 17 + #include <linux/compiler.h> 18 + #include <asm/fpstate.h> 19 + 20 + #define THREAD_SIZE_ORDER 1 21 + #define THREAD_SIZE 8192 22 + #define THREAD_START_SP (THREAD_SIZE - 8) 23 + 24 + #ifndef __ASSEMBLY__ 25 + 26 + struct task_struct; 27 + struct exec_domain; 28 + 29 + #include <asm/types.h> 30 + 31 + typedef struct { 32 + unsigned long seg; 33 + } mm_segment_t; 34 + 35 + struct cpu_context_save { 36 + __u32 r4; 37 + __u32 r5; 38 + __u32 r6; 39 + __u32 r7; 40 + __u32 r8; 41 + __u32 r9; 42 + __u32 r10; 43 + __u32 r11; 44 + __u32 r12; 45 + __u32 r13; 46 + __u32 r14; 47 + __u32 r15; 48 + __u32 r16; 49 + __u32 r17; 50 + __u32 r18; 51 + __u32 r19; 52 + __u32 r20; 53 + __u32 r21; 54 + __u32 r22; 55 + __u32 r23; 56 + __u32 r24; 57 + __u32 r25; 58 + __u32 r26; 59 + __u32 fp; 60 + __u32 sp; 61 + __u32 pc; 62 + }; 63 + 64 + /* 65 + * low level task data that entry.S needs immediate access to. 66 + * __switch_to() assumes cpu_context follows immediately after cpu_domain. 67 + */ 68 + struct thread_info { 69 + unsigned long flags; /* low level flags */ 70 + int preempt_count; /* 0 => preemptable */ 71 + /* <0 => bug */ 72 + mm_segment_t addr_limit; /* address limit */ 73 + struct task_struct *task; /* main task structure */ 74 + struct exec_domain *exec_domain; /* execution domain */ 75 + __u32 cpu; /* cpu */ 76 + struct cpu_context_save cpu_context; /* cpu context */ 77 + __u32 syscall; /* syscall number */ 78 + __u8 used_cp[16]; /* thread used copro */ 79 + #ifdef CONFIG_UNICORE_FPU_F64 80 + struct fp_state fpstate __attribute__((aligned(8))); 81 + #endif 82 + struct restart_block restart_block; 83 + }; 84 + 85 + #define INIT_THREAD_INFO(tsk) \ 86 + { \ 87 + .task = &tsk, \ 88 + .exec_domain = &default_exec_domain, \ 89 + .flags = 0, \ 90 + .preempt_count = INIT_PREEMPT_COUNT, \ 91 + .addr_limit = KERNEL_DS, \ 92 + .restart_block = { \ 93 + .fn = do_no_restart_syscall, \ 94 + }, \ 95 + } 96 + 97 + #define init_thread_info (init_thread_union.thread_info) 98 + #define init_stack (init_thread_union.stack) 99 + 100 + /* 101 + * how to get the thread information struct from C 102 + */ 103 + static inline struct thread_info *current_thread_info(void) __attribute_const__; 104 + 105 + static inline struct thread_info *current_thread_info(void) 106 + { 107 + register unsigned long sp asm ("sp"); 108 + return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); 109 + } 110 + 111 + #define thread_saved_pc(tsk) \ 112 + ((unsigned long)(task_thread_info(tsk)->cpu_context.pc)) 113 + #define thread_saved_sp(tsk) \ 114 + ((unsigned long)(task_thread_info(tsk)->cpu_context.sp)) 115 + #define thread_saved_fp(tsk) \ 116 + ((unsigned long)(task_thread_info(tsk)->cpu_context.fp)) 117 + 118 + #endif 119 + 120 + /* 121 + * We use bit 30 of the preempt_count to indicate that kernel 122 + * preemption is occurring. See <asm/hardirq.h>. 123 + */ 124 + #define PREEMPT_ACTIVE 0x40000000 125 + 126 + /* 127 + * thread information flags: 128 + * TIF_SYSCALL_TRACE - syscall trace active 129 + * TIF_SIGPENDING - signal pending 130 + * TIF_NEED_RESCHED - rescheduling necessary 131 + * TIF_NOTIFY_RESUME - callback before returning to user 132 + */ 133 + #define TIF_SIGPENDING 0 134 + #define TIF_NEED_RESCHED 1 135 + #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ 136 + #define TIF_SYSCALL_TRACE 8 137 + #define TIF_MEMDIE 18 138 + #define TIF_FREEZE 19 139 + #define TIF_RESTORE_SIGMASK 20 140 + 141 + #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) 142 + #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) 143 + #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) 144 + #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) 145 + #define _TIF_FREEZE (1 << TIF_FREEZE) 146 + #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) 147 + 148 + /* 149 + * Change these and you break ASM code in entry-common.S 150 + */ 151 + #define _TIF_WORK_MASK 0x000000ff 152 + 153 + #endif /* __KERNEL__ */ 154 + #endif /* __UNICORE_THREAD_INFO_H__ */
+44
arch/unicore32/kernel/init_task.c
··· 1 + /* 2 + * linux/arch/unicore32/kernel/init_task.c 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + #include <linux/mm.h> 13 + #include <linux/module.h> 14 + #include <linux/fs.h> 15 + #include <linux/sched.h> 16 + #include <linux/init.h> 17 + #include <linux/init_task.h> 18 + #include <linux/mqueue.h> 19 + #include <linux/uaccess.h> 20 + 21 + #include <asm/pgtable.h> 22 + 23 + static struct signal_struct init_signals = INIT_SIGNALS(init_signals); 24 + static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); 25 + /* 26 + * Initial thread structure. 27 + * 28 + * We need to make sure that this is 8192-byte aligned due to the 29 + * way process stacks are handled. This is done by making sure 30 + * the linker maps this in the .text segment right after head.S, 31 + * and making head.S ensure the proper alignment. 32 + * 33 + * The things we do for performance.. 34 + */ 35 + union thread_union init_thread_union __init_task_data = { 36 + INIT_THREAD_INFO(init_task) }; 37 + 38 + /* 39 + * Initial task structure. 40 + * 41 + * All other task structs will be allocated on slabs in fork.c 42 + */ 43 + struct task_struct init_task = INIT_TASK(init_task); 44 + EXPORT_SYMBOL(init_task);
+389
arch/unicore32/kernel/process.c
··· 1 + /* 2 + * linux/arch/unicore32/kernel/process.c 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + #include <stdarg.h> 13 + 14 + #include <linux/module.h> 15 + #include <linux/sched.h> 16 + #include <linux/kernel.h> 17 + #include <linux/mm.h> 18 + #include <linux/stddef.h> 19 + #include <linux/unistd.h> 20 + #include <linux/delay.h> 21 + #include <linux/reboot.h> 22 + #include <linux/interrupt.h> 23 + #include <linux/kallsyms.h> 24 + #include <linux/init.h> 25 + #include <linux/cpu.h> 26 + #include <linux/elfcore.h> 27 + #include <linux/pm.h> 28 + #include <linux/tick.h> 29 + #include <linux/utsname.h> 30 + #include <linux/uaccess.h> 31 + #include <linux/random.h> 32 + #include <linux/gpio.h> 33 + #include <linux/stacktrace.h> 34 + 35 + #include <asm/cacheflush.h> 36 + #include <asm/processor.h> 37 + #include <asm/system.h> 38 + #include <asm/stacktrace.h> 39 + 40 + #include "setup.h" 41 + 42 + static const char * const processor_modes[] = { 43 + "UK00", "UK01", "UK02", "UK03", "UK04", "UK05", "UK06", "UK07", 44 + "UK08", "UK09", "UK0A", "UK0B", "UK0C", "UK0D", "UK0E", "UK0F", 45 + "USER", "REAL", "INTR", "PRIV", "UK14", "UK15", "UK16", "ABRT", 46 + "UK18", "UK19", "UK1A", "EXTN", "UK1C", "UK1D", "UK1E", "SUSR" 47 + }; 48 + 49 + /* 50 + * The idle thread, has rather strange semantics for calling pm_idle, 51 + * but this is what x86 does and we need to do the same, so that 52 + * things like cpuidle get called in the same way. 53 + */ 54 + void cpu_idle(void) 55 + { 56 + /* endless idle loop with no priority at all */ 57 + while (1) { 58 + tick_nohz_stop_sched_tick(1); 59 + while (!need_resched()) { 60 + local_irq_disable(); 61 + stop_critical_timings(); 62 + cpu_do_idle(); 63 + local_irq_enable(); 64 + start_critical_timings(); 65 + } 66 + tick_nohz_restart_sched_tick(); 67 + preempt_enable_no_resched(); 68 + schedule(); 69 + preempt_disable(); 70 + } 71 + } 72 + 73 + static char reboot_mode = 'h'; 74 + 75 + int __init reboot_setup(char *str) 76 + { 77 + reboot_mode = str[0]; 78 + return 1; 79 + } 80 + 81 + __setup("reboot=", reboot_setup); 82 + 83 + void machine_halt(void) 84 + { 85 + gpio_set_value(GPO_SOFT_OFF, 0); 86 + } 87 + 88 + /* 89 + * Function pointers to optional machine specific functions 90 + */ 91 + void (*pm_power_off)(void) = NULL; 92 + 93 + void machine_power_off(void) 94 + { 95 + if (pm_power_off) 96 + pm_power_off(); 97 + machine_halt(); 98 + } 99 + 100 + void machine_restart(char *cmd) 101 + { 102 + /* Disable interrupts first */ 103 + local_irq_disable(); 104 + 105 + /* 106 + * Tell the mm system that we are going to reboot - 107 + * we may need it to insert some 1:1 mappings so that 108 + * soft boot works. 109 + */ 110 + setup_mm_for_reboot(reboot_mode); 111 + 112 + /* Clean and invalidate caches */ 113 + flush_cache_all(); 114 + 115 + /* Turn off caching */ 116 + cpu_proc_fin(); 117 + 118 + /* Push out any further dirty data, and ensure cache is empty */ 119 + flush_cache_all(); 120 + 121 + /* 122 + * Now handle reboot code. 123 + */ 124 + if (reboot_mode == 's') { 125 + /* Jump into ROM at address 0xffff0000 */ 126 + cpu_reset(VECTORS_BASE); 127 + } else { 128 + PM_PLLSYSCFG = 0x00002001; /* cpu clk = 250M */ 129 + PM_PLLDDRCFG = 0x00100800; /* ddr clk = 44M */ 130 + PM_PLLVGACFG = 0x00002001; /* vga clk = 250M */ 131 + 132 + /* Use on-chip reset capability */ 133 + /* following instructions must be in one icache line */ 134 + __asm__ __volatile__( 135 + " .align 5\n\t" 136 + " stw %1, [%0]\n\t" 137 + "201: ldw r0, [%0]\n\t" 138 + " cmpsub.a r0, #0\n\t" 139 + " bne 201b\n\t" 140 + " stw %3, [%2]\n\t" 141 + " nop; nop; nop\n\t" 142 + /* prefetch 3 instructions at most */ 143 + : 144 + : "r" ((unsigned long)&PM_PMCR), 145 + "r" (PM_PMCR_CFBSYS | PM_PMCR_CFBDDR 146 + | PM_PMCR_CFBVGA), 147 + "r" ((unsigned long)&RESETC_SWRR), 148 + "r" (RESETC_SWRR_SRB) 149 + : "r0", "memory"); 150 + } 151 + 152 + /* 153 + * Whoops - the architecture was unable to reboot. 154 + * Tell the user! 155 + */ 156 + mdelay(1000); 157 + printk(KERN_EMERG "Reboot failed -- System halted\n"); 158 + do { } while (1); 159 + } 160 + 161 + void __show_regs(struct pt_regs *regs) 162 + { 163 + unsigned long flags; 164 + char buf[64]; 165 + 166 + printk(KERN_DEFAULT "CPU: %d %s (%s %.*s)\n", 167 + raw_smp_processor_id(), print_tainted(), 168 + init_utsname()->release, 169 + (int)strcspn(init_utsname()->version, " "), 170 + init_utsname()->version); 171 + print_symbol("PC is at %s\n", instruction_pointer(regs)); 172 + print_symbol("LR is at %s\n", regs->UCreg_lr); 173 + printk(KERN_DEFAULT "pc : [<%08lx>] lr : [<%08lx>] psr: %08lx\n" 174 + "sp : %08lx ip : %08lx fp : %08lx\n", 175 + regs->UCreg_pc, regs->UCreg_lr, regs->UCreg_asr, 176 + regs->UCreg_sp, regs->UCreg_ip, regs->UCreg_fp); 177 + printk(KERN_DEFAULT "r26: %08lx r25: %08lx r24: %08lx\n", 178 + regs->UCreg_26, regs->UCreg_25, 179 + regs->UCreg_24); 180 + printk(KERN_DEFAULT "r23: %08lx r22: %08lx r21: %08lx r20: %08lx\n", 181 + regs->UCreg_23, regs->UCreg_22, 182 + regs->UCreg_21, regs->UCreg_20); 183 + printk(KERN_DEFAULT "r19: %08lx r18: %08lx r17: %08lx r16: %08lx\n", 184 + regs->UCreg_19, regs->UCreg_18, 185 + regs->UCreg_17, regs->UCreg_16); 186 + printk(KERN_DEFAULT "r15: %08lx r14: %08lx r13: %08lx r12: %08lx\n", 187 + regs->UCreg_15, regs->UCreg_14, 188 + regs->UCreg_13, regs->UCreg_12); 189 + printk(KERN_DEFAULT "r11: %08lx r10: %08lx r9 : %08lx r8 : %08lx\n", 190 + regs->UCreg_11, regs->UCreg_10, 191 + regs->UCreg_09, regs->UCreg_08); 192 + printk(KERN_DEFAULT "r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n", 193 + regs->UCreg_07, regs->UCreg_06, 194 + regs->UCreg_05, regs->UCreg_04); 195 + printk(KERN_DEFAULT "r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", 196 + regs->UCreg_03, regs->UCreg_02, 197 + regs->UCreg_01, regs->UCreg_00); 198 + 199 + flags = regs->UCreg_asr; 200 + buf[0] = flags & PSR_S_BIT ? 'S' : 's'; 201 + buf[1] = flags & PSR_Z_BIT ? 'Z' : 'z'; 202 + buf[2] = flags & PSR_C_BIT ? 'C' : 'c'; 203 + buf[3] = flags & PSR_V_BIT ? 'V' : 'v'; 204 + buf[4] = '\0'; 205 + 206 + printk(KERN_DEFAULT "Flags: %s INTR o%s REAL o%s Mode %s Segment %s\n", 207 + buf, interrupts_enabled(regs) ? "n" : "ff", 208 + fast_interrupts_enabled(regs) ? "n" : "ff", 209 + processor_modes[processor_mode(regs)], 210 + segment_eq(get_fs(), get_ds()) ? "kernel" : "user"); 211 + { 212 + unsigned int ctrl; 213 + 214 + buf[0] = '\0'; 215 + { 216 + unsigned int transbase; 217 + asm("movc %0, p0.c2, #0\n" 218 + : "=r" (transbase)); 219 + snprintf(buf, sizeof(buf), " Table: %08x", transbase); 220 + } 221 + asm("movc %0, p0.c1, #0\n" : "=r" (ctrl)); 222 + 223 + printk(KERN_DEFAULT "Control: %08x%s\n", ctrl, buf); 224 + } 225 + } 226 + 227 + void show_regs(struct pt_regs *regs) 228 + { 229 + printk(KERN_DEFAULT "\n"); 230 + printk(KERN_DEFAULT "Pid: %d, comm: %20s\n", 231 + task_pid_nr(current), current->comm); 232 + __show_regs(regs); 233 + __backtrace(); 234 + } 235 + 236 + /* 237 + * Free current thread data structures etc.. 238 + */ 239 + void exit_thread(void) 240 + { 241 + } 242 + 243 + void flush_thread(void) 244 + { 245 + struct thread_info *thread = current_thread_info(); 246 + struct task_struct *tsk = current; 247 + 248 + memset(thread->used_cp, 0, sizeof(thread->used_cp)); 249 + memset(&tsk->thread.debug, 0, sizeof(struct debug_info)); 250 + #ifdef CONFIG_UNICORE_FPU_F64 251 + memset(&thread->fpstate, 0, sizeof(struct fp_state)); 252 + #endif 253 + } 254 + 255 + void release_thread(struct task_struct *dead_task) 256 + { 257 + } 258 + 259 + asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); 260 + 261 + int 262 + copy_thread(unsigned long clone_flags, unsigned long stack_start, 263 + unsigned long stk_sz, struct task_struct *p, struct pt_regs *regs) 264 + { 265 + struct thread_info *thread = task_thread_info(p); 266 + struct pt_regs *childregs = task_pt_regs(p); 267 + 268 + *childregs = *regs; 269 + childregs->UCreg_00 = 0; 270 + childregs->UCreg_sp = stack_start; 271 + 272 + memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save)); 273 + thread->cpu_context.sp = (unsigned long)childregs; 274 + thread->cpu_context.pc = (unsigned long)ret_from_fork; 275 + 276 + if (clone_flags & CLONE_SETTLS) 277 + childregs->UCreg_16 = regs->UCreg_03; 278 + 279 + return 0; 280 + } 281 + 282 + /* 283 + * Fill in the task's elfregs structure for a core dump. 284 + */ 285 + int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs) 286 + { 287 + elf_core_copy_regs(elfregs, task_pt_regs(t)); 288 + return 1; 289 + } 290 + 291 + /* 292 + * fill in the fpe structure for a core dump... 293 + */ 294 + int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fp) 295 + { 296 + struct thread_info *thread = current_thread_info(); 297 + int used_math = thread->used_cp[1] | thread->used_cp[2]; 298 + 299 + #ifdef CONFIG_UNICORE_FPU_F64 300 + if (used_math) 301 + memcpy(fp, &thread->fpstate, sizeof(*fp)); 302 + #endif 303 + return used_math != 0; 304 + } 305 + EXPORT_SYMBOL(dump_fpu); 306 + 307 + /* 308 + * Shuffle the argument into the correct register before calling the 309 + * thread function. r1 is the thread argument, r2 is the pointer to 310 + * the thread function, and r3 points to the exit function. 311 + */ 312 + asm(".pushsection .text\n" 313 + " .align\n" 314 + " .type kernel_thread_helper, #function\n" 315 + "kernel_thread_helper:\n" 316 + " mov.a asr, r7\n" 317 + " mov r0, r4\n" 318 + " mov lr, r6\n" 319 + " mov pc, r5\n" 320 + " .size kernel_thread_helper, . - kernel_thread_helper\n" 321 + " .popsection"); 322 + 323 + /* 324 + * Create a kernel thread. 325 + */ 326 + pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) 327 + { 328 + struct pt_regs regs; 329 + 330 + memset(&regs, 0, sizeof(regs)); 331 + 332 + regs.UCreg_04 = (unsigned long)arg; 333 + regs.UCreg_05 = (unsigned long)fn; 334 + regs.UCreg_06 = (unsigned long)do_exit; 335 + regs.UCreg_07 = PRIV_MODE; 336 + regs.UCreg_pc = (unsigned long)kernel_thread_helper; 337 + regs.UCreg_asr = regs.UCreg_07 | PSR_I_BIT; 338 + 339 + return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL); 340 + } 341 + EXPORT_SYMBOL(kernel_thread); 342 + 343 + unsigned long get_wchan(struct task_struct *p) 344 + { 345 + struct stackframe frame; 346 + int count = 0; 347 + if (!p || p == current || p->state == TASK_RUNNING) 348 + return 0; 349 + 350 + frame.fp = thread_saved_fp(p); 351 + frame.sp = thread_saved_sp(p); 352 + frame.lr = 0; /* recovered from the stack */ 353 + frame.pc = thread_saved_pc(p); 354 + do { 355 + int ret = unwind_frame(&frame); 356 + if (ret < 0) 357 + return 0; 358 + if (!in_sched_functions(frame.pc)) 359 + return frame.pc; 360 + } while ((count++) < 16); 361 + return 0; 362 + } 363 + 364 + unsigned long arch_randomize_brk(struct mm_struct *mm) 365 + { 366 + unsigned long range_end = mm->brk + 0x02000000; 367 + return randomize_range(mm->brk, range_end, 0) ? : mm->brk; 368 + } 369 + 370 + /* 371 + * The vectors page is always readable from user space for the 372 + * atomic helpers and the signal restart code. Let's declare a mapping 373 + * for it so it is visible through ptrace and /proc/<pid>/mem. 374 + */ 375 + 376 + int vectors_user_mapping(void) 377 + { 378 + struct mm_struct *mm = current->mm; 379 + return install_special_mapping(mm, 0xffff0000, PAGE_SIZE, 380 + VM_READ | VM_EXEC | 381 + VM_MAYREAD | VM_MAYEXEC | 382 + VM_ALWAYSDUMP | VM_RESERVED, 383 + NULL); 384 + } 385 + 386 + const char *arch_vma_name(struct vm_area_struct *vma) 387 + { 388 + return (vma->vm_start == 0xffff0000) ? "[vectors]" : NULL; 389 + }
+131
arch/unicore32/kernel/stacktrace.c
··· 1 + /* 2 + * linux/arch/unicore32/kernel/stacktrace.c 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + #include <linux/module.h> 13 + #include <linux/sched.h> 14 + #include <linux/stacktrace.h> 15 + 16 + #include <asm/stacktrace.h> 17 + 18 + #if defined(CONFIG_FRAME_POINTER) 19 + /* 20 + * Unwind the current stack frame and store the new register values in the 21 + * structure passed as argument. Unwinding is equivalent to a function return, 22 + * hence the new PC value rather than LR should be used for backtrace. 23 + * 24 + * With framepointer enabled, a simple function prologue looks like this: 25 + * mov ip, sp 26 + * stmdb sp!, {fp, ip, lr, pc} 27 + * sub fp, ip, #4 28 + * 29 + * A simple function epilogue looks like this: 30 + * ldm sp, {fp, sp, pc} 31 + * 32 + * Note that with framepointer enabled, even the leaf functions have the same 33 + * prologue and epilogue, therefore we can ignore the LR value in this case. 34 + */ 35 + int notrace unwind_frame(struct stackframe *frame) 36 + { 37 + unsigned long high, low; 38 + unsigned long fp = frame->fp; 39 + 40 + /* only go to a higher address on the stack */ 41 + low = frame->sp; 42 + high = ALIGN(low, THREAD_SIZE); 43 + 44 + /* check current frame pointer is within bounds */ 45 + if (fp < (low + 12) || fp + 4 >= high) 46 + return -EINVAL; 47 + 48 + /* restore the registers from the stack frame */ 49 + frame->fp = *(unsigned long *)(fp - 12); 50 + frame->sp = *(unsigned long *)(fp - 8); 51 + frame->pc = *(unsigned long *)(fp - 4); 52 + 53 + return 0; 54 + } 55 + #endif 56 + 57 + void notrace walk_stackframe(struct stackframe *frame, 58 + int (*fn)(struct stackframe *, void *), void *data) 59 + { 60 + while (1) { 61 + int ret; 62 + 63 + if (fn(frame, data)) 64 + break; 65 + ret = unwind_frame(frame); 66 + if (ret < 0) 67 + break; 68 + } 69 + } 70 + EXPORT_SYMBOL(walk_stackframe); 71 + 72 + #ifdef CONFIG_STACKTRACE 73 + struct stack_trace_data { 74 + struct stack_trace *trace; 75 + unsigned int no_sched_functions; 76 + unsigned int skip; 77 + }; 78 + 79 + static int save_trace(struct stackframe *frame, void *d) 80 + { 81 + struct stack_trace_data *data = d; 82 + struct stack_trace *trace = data->trace; 83 + unsigned long addr = frame->pc; 84 + 85 + if (data->no_sched_functions && in_sched_functions(addr)) 86 + return 0; 87 + if (data->skip) { 88 + data->skip--; 89 + return 0; 90 + } 91 + 92 + trace->entries[trace->nr_entries++] = addr; 93 + 94 + return trace->nr_entries >= trace->max_entries; 95 + } 96 + 97 + void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 98 + { 99 + struct stack_trace_data data; 100 + struct stackframe frame; 101 + 102 + data.trace = trace; 103 + data.skip = trace->skip; 104 + 105 + if (tsk != current) { 106 + data.no_sched_functions = 1; 107 + frame.fp = thread_saved_fp(tsk); 108 + frame.sp = thread_saved_sp(tsk); 109 + frame.lr = 0; /* recovered from the stack */ 110 + frame.pc = thread_saved_pc(tsk); 111 + } else { 112 + register unsigned long current_sp asm("sp"); 113 + 114 + data.no_sched_functions = 0; 115 + frame.fp = (unsigned long)__builtin_frame_address(0); 116 + frame.sp = current_sp; 117 + frame.lr = (unsigned long)__builtin_return_address(0); 118 + frame.pc = (unsigned long)save_stack_trace_tsk; 119 + } 120 + 121 + walk_stackframe(&frame, save_trace, &data); 122 + if (trace->nr_entries < trace->max_entries) 123 + trace->entries[trace->nr_entries++] = ULONG_MAX; 124 + } 125 + 126 + void save_stack_trace(struct stack_trace *trace) 127 + { 128 + save_stack_trace_tsk(current, trace); 129 + } 130 + EXPORT_SYMBOL_GPL(save_stack_trace); 131 + #endif
+163
arch/unicore32/lib/backtrace.S
··· 1 + /* 2 + * linux/arch/unicore32/lib/backtrace.S 3 + * 4 + * Code specific to PKUnity SoC and UniCore ISA 5 + * 6 + * Copyright (C) 2001-2010 GUAN Xue-tao 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + #include <linux/linkage.h> 13 + #include <asm/assembler.h> 14 + .text 15 + 16 + @ fp is 0 or stack frame 17 + 18 + #define frame v4 19 + #define sv_fp v5 20 + #define sv_pc v6 21 + #define offset v8 22 + 23 + ENTRY(__backtrace) 24 + mov r0, fp 25 + 26 + ENTRY(c_backtrace) 27 + 28 + #if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK) 29 + mov pc, lr 30 + ENDPROC(__backtrace) 31 + ENDPROC(c_backtrace) 32 + #else 33 + stm.w (v4 - v8, lr), [sp-] @ Save an extra register 34 + @ so we have a location... 35 + mov.a frame, r0 @ if frame pointer is zero 36 + beq no_frame @ we have no stack frames 37 + 38 + 1: stm.w (pc), [sp-] @ calculate offset of PC stored 39 + ldw.w r0, [sp]+, #4 @ by stmfd for this CPU 40 + adr r1, 1b 41 + sub offset, r0, r1 42 + 43 + /* 44 + * Stack frame layout: 45 + * optionally saved caller registers (r4 - r10) 46 + * saved fp 47 + * saved sp 48 + * saved lr 49 + * frame => saved pc 50 + * optionally saved arguments (r0 - r3) 51 + * saved sp => <next word> 52 + * 53 + * Functions start with the following code sequence: 54 + * mov ip, sp 55 + * stm.w (r0 - r3), [sp-] (optional) 56 + * corrected pc => stm.w sp, (..., fp, ip, lr, pc) 57 + */ 58 + for_each_frame: 59 + 60 + 1001: ldw sv_pc, [frame+], #0 @ get saved pc 61 + 1002: ldw sv_fp, [frame+], #-12 @ get saved fp 62 + 63 + sub sv_pc, sv_pc, offset @ Correct PC for prefetching 64 + 65 + 1003: ldw r2, [sv_pc+], #-4 @ if stmfd sp, {args} exists, 66 + ldw r3, .Ldsi+4 @ adjust saved 'pc' back one 67 + cxor.a r3, r2 >> #14 @ instruction 68 + beq 201f 69 + sub r0, sv_pc, #4 @ allow for mov 70 + b 202f 71 + 201: 72 + sub r0, sv_pc, #8 @ allow for mov + stmia 73 + 202: 74 + ldw r1, [frame+], #-4 @ get saved lr 75 + mov r2, frame 76 + b.l dump_backtrace_entry 77 + 78 + ldw r1, [sv_pc+], #-4 @ if stmfd sp, {args} exists, 79 + ldw r3, .Ldsi+4 80 + cxor.a r3, r1 >> #14 81 + bne 1004f 82 + ldw r0, [frame+], #-8 @ get sp 83 + sub r0, r0, #4 @ point at the last arg 84 + b.l .Ldumpstm @ dump saved registers 85 + 86 + 1004: ldw r1, [sv_pc+], #0 @ if stmfd {, fp, ip, lr, pc} 87 + ldw r3, .Ldsi @ instruction exists, 88 + cxor.a r3, r1 >> #14 89 + bne 201f 90 + sub r0, frame, #16 91 + b.l .Ldumpstm @ dump saved registers 92 + 201: 93 + cxor.a sv_fp, #0 @ zero saved fp means 94 + beq no_frame @ no further frames 95 + 96 + csub.a sv_fp, frame @ next frame must be 97 + mov frame, sv_fp @ above the current frame 98 + bua for_each_frame 99 + 100 + 1006: adr r0, .Lbad 101 + mov r1, frame 102 + b.l printk 103 + no_frame: ldm.w (v4 - v8, pc), [sp]+ 104 + ENDPROC(__backtrace) 105 + ENDPROC(c_backtrace) 106 + 107 + .pushsection __ex_table,"a" 108 + .align 3 109 + .long 1001b, 1006b 110 + .long 1002b, 1006b 111 + .long 1003b, 1006b 112 + .long 1004b, 1006b 113 + .popsection 114 + 115 + #define instr v4 116 + #define reg v5 117 + #define stack v6 118 + 119 + .Ldumpstm: stm.w (instr, reg, stack, v7, lr), [sp-] 120 + mov stack, r0 121 + mov instr, r1 122 + mov reg, #14 123 + mov v7, #0 124 + 1: mov r3, #1 125 + csub.a reg, #8 126 + bne 201f 127 + sub reg, reg, #3 128 + 201: 129 + cand.a instr, r3 << reg 130 + beq 2f 131 + add v7, v7, #1 132 + cxor.a v7, #6 133 + cmoveq v7, #1 134 + cmoveq r1, #'\n' 135 + cmovne r1, #' ' 136 + ldw.w r3, [stack]+, #-4 137 + mov r2, reg 138 + csub.a r2, #8 139 + bsl 201f 140 + sub r2, r2, #3 141 + 201: 142 + cand.a instr, #0x40 @ if H is 1, high 16 regs 143 + beq 201f 144 + add r2, r2, #0x10 @ so r2 need add 16 145 + 201: 146 + adr r0, .Lfp 147 + b.l printk 148 + 2: sub.a reg, reg, #1 149 + bns 1b 150 + cxor.a v7, #0 151 + beq 201f 152 + adr r0, .Lcr 153 + b.l printk 154 + 201: ldm.w (instr, reg, stack, v7, pc), [sp]+ 155 + 156 + .Lfp: .asciz "%cr%d:%08x" 157 + .Lcr: .asciz "\n" 158 + .Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n" 159 + .align 160 + .Ldsi: .word 0x92eec000 >> 14 @ stm.w sp, (... fp, ip, lr, pc) 161 + .word 0x92e10000 >> 14 @ stm.w sp, () 162 + 163 + #endif