···11+/*22+ * linux/arch/unicore32/include/asm/stacktrace.h33+ *44+ * Code specific to PKUnity SoC and UniCore ISA55+ *66+ * Copyright (C) 2001-2010 GUAN Xue-tao77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License version 2 as1010+ * published by the Free Software Foundation.1111+ */1212+1313+#ifndef __UNICORE_STACKTRACE_H__1414+#define __UNICORE_STACKTRACE_H__1515+1616+struct stackframe {1717+ unsigned long fp;1818+ unsigned long sp;1919+ unsigned long lr;2020+ unsigned long pc;2121+};2222+2323+#ifdef CONFIG_FRAME_POINTER2424+extern int unwind_frame(struct stackframe *frame);2525+#else2626+#define unwind_frame(f) (-EINVAL)2727+#endif2828+extern void walk_stackframe(struct stackframe *frame,2929+ int (*fn)(struct stackframe *, void *), void *data);3030+3131+#endif /* __UNICORE_STACKTRACE_H__ */
+154
arch/unicore32/include/asm/thread_info.h
···11+/*22+ * linux/arch/unicore32/include/asm/thread_info.h33+ *44+ * Code specific to PKUnity SoC and UniCore ISA55+ *66+ * Copyright (C) 2001-2010 GUAN Xue-tao77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License version 2 as1010+ * published by the Free Software Foundation.1111+ */1212+#ifndef __UNICORE_THREAD_INFO_H__1313+#define __UNICORE_THREAD_INFO_H__1414+1515+#ifdef __KERNEL__1616+1717+#include <linux/compiler.h>1818+#include <asm/fpstate.h>1919+2020+#define THREAD_SIZE_ORDER 12121+#define THREAD_SIZE 81922222+#define THREAD_START_SP (THREAD_SIZE - 8)2323+2424+#ifndef __ASSEMBLY__2525+2626+struct task_struct;2727+struct exec_domain;2828+2929+#include <asm/types.h>3030+3131+typedef struct {3232+ unsigned long seg;3333+} mm_segment_t;3434+3535+struct cpu_context_save {3636+ __u32 r4;3737+ __u32 r5;3838+ __u32 r6;3939+ __u32 r7;4040+ __u32 r8;4141+ __u32 r9;4242+ __u32 r10;4343+ __u32 r11;4444+ __u32 r12;4545+ __u32 r13;4646+ __u32 r14;4747+ __u32 r15;4848+ __u32 r16;4949+ __u32 r17;5050+ __u32 r18;5151+ __u32 r19;5252+ __u32 r20;5353+ __u32 r21;5454+ __u32 r22;5555+ __u32 r23;5656+ __u32 r24;5757+ __u32 r25;5858+ __u32 r26;5959+ __u32 fp;6060+ __u32 sp;6161+ __u32 pc;6262+};6363+6464+/*6565+ * low level task data that entry.S needs immediate access to.6666+ * __switch_to() assumes cpu_context follows immediately after cpu_domain.6767+ */6868+struct thread_info {6969+ unsigned long flags; /* low level flags */7070+ int preempt_count; /* 0 => preemptable */7171+ /* <0 => bug */7272+ mm_segment_t addr_limit; /* address limit */7373+ struct task_struct *task; /* main task structure */7474+ struct exec_domain *exec_domain; /* execution domain */7575+ __u32 cpu; /* cpu */7676+ struct cpu_context_save cpu_context; /* cpu context */7777+ __u32 syscall; /* syscall number */7878+ __u8 used_cp[16]; /* thread used copro */7979+#ifdef CONFIG_UNICORE_FPU_F648080+ struct fp_state fpstate __attribute__((aligned(8)));8181+#endif8282+ struct restart_block restart_block;8383+};8484+8585+#define INIT_THREAD_INFO(tsk) \8686+{ \8787+ .task = &tsk, \8888+ .exec_domain = &default_exec_domain, \8989+ .flags = 0, \9090+ .preempt_count = INIT_PREEMPT_COUNT, \9191+ .addr_limit = KERNEL_DS, \9292+ .restart_block = { \9393+ .fn = do_no_restart_syscall, \9494+ }, \9595+}9696+9797+#define init_thread_info (init_thread_union.thread_info)9898+#define init_stack (init_thread_union.stack)9999+100100+/*101101+ * how to get the thread information struct from C102102+ */103103+static inline struct thread_info *current_thread_info(void) __attribute_const__;104104+105105+static inline struct thread_info *current_thread_info(void)106106+{107107+ register unsigned long sp asm ("sp");108108+ return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));109109+}110110+111111+#define thread_saved_pc(tsk) \112112+ ((unsigned long)(task_thread_info(tsk)->cpu_context.pc))113113+#define thread_saved_sp(tsk) \114114+ ((unsigned long)(task_thread_info(tsk)->cpu_context.sp))115115+#define thread_saved_fp(tsk) \116116+ ((unsigned long)(task_thread_info(tsk)->cpu_context.fp))117117+118118+#endif119119+120120+/*121121+ * We use bit 30 of the preempt_count to indicate that kernel122122+ * preemption is occurring. See <asm/hardirq.h>.123123+ */124124+#define PREEMPT_ACTIVE 0x40000000125125+126126+/*127127+ * thread information flags:128128+ * TIF_SYSCALL_TRACE - syscall trace active129129+ * TIF_SIGPENDING - signal pending130130+ * TIF_NEED_RESCHED - rescheduling necessary131131+ * TIF_NOTIFY_RESUME - callback before returning to user132132+ */133133+#define TIF_SIGPENDING 0134134+#define TIF_NEED_RESCHED 1135135+#define TIF_NOTIFY_RESUME 2 /* callback before returning to user */136136+#define TIF_SYSCALL_TRACE 8137137+#define TIF_MEMDIE 18138138+#define TIF_FREEZE 19139139+#define TIF_RESTORE_SIGMASK 20140140+141141+#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)142142+#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)143143+#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)144144+#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)145145+#define _TIF_FREEZE (1 << TIF_FREEZE)146146+#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)147147+148148+/*149149+ * Change these and you break ASM code in entry-common.S150150+ */151151+#define _TIF_WORK_MASK 0x000000ff152152+153153+#endif /* __KERNEL__ */154154+#endif /* __UNICORE_THREAD_INFO_H__ */
+44
arch/unicore32/kernel/init_task.c
···11+/*22+ * linux/arch/unicore32/kernel/init_task.c33+ *44+ * Code specific to PKUnity SoC and UniCore ISA55+ *66+ * Copyright (C) 2001-2010 GUAN Xue-tao77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License version 2 as1010+ * published by the Free Software Foundation.1111+ */1212+#include <linux/mm.h>1313+#include <linux/module.h>1414+#include <linux/fs.h>1515+#include <linux/sched.h>1616+#include <linux/init.h>1717+#include <linux/init_task.h>1818+#include <linux/mqueue.h>1919+#include <linux/uaccess.h>2020+2121+#include <asm/pgtable.h>2222+2323+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);2424+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);2525+/*2626+ * Initial thread structure.2727+ *2828+ * We need to make sure that this is 8192-byte aligned due to the2929+ * way process stacks are handled. This is done by making sure3030+ * the linker maps this in the .text segment right after head.S,3131+ * and making head.S ensure the proper alignment.3232+ *3333+ * The things we do for performance..3434+ */3535+union thread_union init_thread_union __init_task_data = {3636+ INIT_THREAD_INFO(init_task) };3737+3838+/*3939+ * Initial task structure.4040+ *4141+ * All other task structs will be allocated on slabs in fork.c4242+ */4343+struct task_struct init_task = INIT_TASK(init_task);4444+EXPORT_SYMBOL(init_task);
+389
arch/unicore32/kernel/process.c
···11+/*22+ * linux/arch/unicore32/kernel/process.c33+ *44+ * Code specific to PKUnity SoC and UniCore ISA55+ *66+ * Copyright (C) 2001-2010 GUAN Xue-tao77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License version 2 as1010+ * published by the Free Software Foundation.1111+ */1212+#include <stdarg.h>1313+1414+#include <linux/module.h>1515+#include <linux/sched.h>1616+#include <linux/kernel.h>1717+#include <linux/mm.h>1818+#include <linux/stddef.h>1919+#include <linux/unistd.h>2020+#include <linux/delay.h>2121+#include <linux/reboot.h>2222+#include <linux/interrupt.h>2323+#include <linux/kallsyms.h>2424+#include <linux/init.h>2525+#include <linux/cpu.h>2626+#include <linux/elfcore.h>2727+#include <linux/pm.h>2828+#include <linux/tick.h>2929+#include <linux/utsname.h>3030+#include <linux/uaccess.h>3131+#include <linux/random.h>3232+#include <linux/gpio.h>3333+#include <linux/stacktrace.h>3434+3535+#include <asm/cacheflush.h>3636+#include <asm/processor.h>3737+#include <asm/system.h>3838+#include <asm/stacktrace.h>3939+4040+#include "setup.h"4141+4242+static const char * const processor_modes[] = {4343+ "UK00", "UK01", "UK02", "UK03", "UK04", "UK05", "UK06", "UK07",4444+ "UK08", "UK09", "UK0A", "UK0B", "UK0C", "UK0D", "UK0E", "UK0F",4545+ "USER", "REAL", "INTR", "PRIV", "UK14", "UK15", "UK16", "ABRT",4646+ "UK18", "UK19", "UK1A", "EXTN", "UK1C", "UK1D", "UK1E", "SUSR"4747+};4848+4949+/*5050+ * The idle thread, has rather strange semantics for calling pm_idle,5151+ * but this is what x86 does and we need to do the same, so that5252+ * things like cpuidle get called in the same way.5353+ */5454+void cpu_idle(void)5555+{5656+ /* endless idle loop with no priority at all */5757+ while (1) {5858+ tick_nohz_stop_sched_tick(1);5959+ while (!need_resched()) {6060+ local_irq_disable();6161+ stop_critical_timings();6262+ cpu_do_idle();6363+ local_irq_enable();6464+ start_critical_timings();6565+ }6666+ tick_nohz_restart_sched_tick();6767+ preempt_enable_no_resched();6868+ schedule();6969+ preempt_disable();7070+ }7171+}7272+7373+static char reboot_mode = 'h';7474+7575+int __init reboot_setup(char *str)7676+{7777+ reboot_mode = str[0];7878+ return 1;7979+}8080+8181+__setup("reboot=", reboot_setup);8282+8383+void machine_halt(void)8484+{8585+ gpio_set_value(GPO_SOFT_OFF, 0);8686+}8787+8888+/*8989+ * Function pointers to optional machine specific functions9090+ */9191+void (*pm_power_off)(void) = NULL;9292+9393+void machine_power_off(void)9494+{9595+ if (pm_power_off)9696+ pm_power_off();9797+ machine_halt();9898+}9999+100100+void machine_restart(char *cmd)101101+{102102+ /* Disable interrupts first */103103+ local_irq_disable();104104+105105+ /*106106+ * Tell the mm system that we are going to reboot -107107+ * we may need it to insert some 1:1 mappings so that108108+ * soft boot works.109109+ */110110+ setup_mm_for_reboot(reboot_mode);111111+112112+ /* Clean and invalidate caches */113113+ flush_cache_all();114114+115115+ /* Turn off caching */116116+ cpu_proc_fin();117117+118118+ /* Push out any further dirty data, and ensure cache is empty */119119+ flush_cache_all();120120+121121+ /*122122+ * Now handle reboot code.123123+ */124124+ if (reboot_mode == 's') {125125+ /* Jump into ROM at address 0xffff0000 */126126+ cpu_reset(VECTORS_BASE);127127+ } else {128128+ PM_PLLSYSCFG = 0x00002001; /* cpu clk = 250M */129129+ PM_PLLDDRCFG = 0x00100800; /* ddr clk = 44M */130130+ PM_PLLVGACFG = 0x00002001; /* vga clk = 250M */131131+132132+ /* Use on-chip reset capability */133133+ /* following instructions must be in one icache line */134134+ __asm__ __volatile__(135135+ " .align 5\n\t"136136+ " stw %1, [%0]\n\t"137137+ "201: ldw r0, [%0]\n\t"138138+ " cmpsub.a r0, #0\n\t"139139+ " bne 201b\n\t"140140+ " stw %3, [%2]\n\t"141141+ " nop; nop; nop\n\t"142142+ /* prefetch 3 instructions at most */143143+ :144144+ : "r" ((unsigned long)&PM_PMCR),145145+ "r" (PM_PMCR_CFBSYS | PM_PMCR_CFBDDR146146+ | PM_PMCR_CFBVGA),147147+ "r" ((unsigned long)&RESETC_SWRR),148148+ "r" (RESETC_SWRR_SRB)149149+ : "r0", "memory");150150+ }151151+152152+ /*153153+ * Whoops - the architecture was unable to reboot.154154+ * Tell the user!155155+ */156156+ mdelay(1000);157157+ printk(KERN_EMERG "Reboot failed -- System halted\n");158158+ do { } while (1);159159+}160160+161161+void __show_regs(struct pt_regs *regs)162162+{163163+ unsigned long flags;164164+ char buf[64];165165+166166+ printk(KERN_DEFAULT "CPU: %d %s (%s %.*s)\n",167167+ raw_smp_processor_id(), print_tainted(),168168+ init_utsname()->release,169169+ (int)strcspn(init_utsname()->version, " "),170170+ init_utsname()->version);171171+ print_symbol("PC is at %s\n", instruction_pointer(regs));172172+ print_symbol("LR is at %s\n", regs->UCreg_lr);173173+ printk(KERN_DEFAULT "pc : [<%08lx>] lr : [<%08lx>] psr: %08lx\n"174174+ "sp : %08lx ip : %08lx fp : %08lx\n",175175+ regs->UCreg_pc, regs->UCreg_lr, regs->UCreg_asr,176176+ regs->UCreg_sp, regs->UCreg_ip, regs->UCreg_fp);177177+ printk(KERN_DEFAULT "r26: %08lx r25: %08lx r24: %08lx\n",178178+ regs->UCreg_26, regs->UCreg_25,179179+ regs->UCreg_24);180180+ printk(KERN_DEFAULT "r23: %08lx r22: %08lx r21: %08lx r20: %08lx\n",181181+ regs->UCreg_23, regs->UCreg_22,182182+ regs->UCreg_21, regs->UCreg_20);183183+ printk(KERN_DEFAULT "r19: %08lx r18: %08lx r17: %08lx r16: %08lx\n",184184+ regs->UCreg_19, regs->UCreg_18,185185+ regs->UCreg_17, regs->UCreg_16);186186+ printk(KERN_DEFAULT "r15: %08lx r14: %08lx r13: %08lx r12: %08lx\n",187187+ regs->UCreg_15, regs->UCreg_14,188188+ regs->UCreg_13, regs->UCreg_12);189189+ printk(KERN_DEFAULT "r11: %08lx r10: %08lx r9 : %08lx r8 : %08lx\n",190190+ regs->UCreg_11, regs->UCreg_10,191191+ regs->UCreg_09, regs->UCreg_08);192192+ printk(KERN_DEFAULT "r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n",193193+ regs->UCreg_07, regs->UCreg_06,194194+ regs->UCreg_05, regs->UCreg_04);195195+ printk(KERN_DEFAULT "r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n",196196+ regs->UCreg_03, regs->UCreg_02,197197+ regs->UCreg_01, regs->UCreg_00);198198+199199+ flags = regs->UCreg_asr;200200+ buf[0] = flags & PSR_S_BIT ? 'S' : 's';201201+ buf[1] = flags & PSR_Z_BIT ? 'Z' : 'z';202202+ buf[2] = flags & PSR_C_BIT ? 'C' : 'c';203203+ buf[3] = flags & PSR_V_BIT ? 'V' : 'v';204204+ buf[4] = '\0';205205+206206+ printk(KERN_DEFAULT "Flags: %s INTR o%s REAL o%s Mode %s Segment %s\n",207207+ buf, interrupts_enabled(regs) ? "n" : "ff",208208+ fast_interrupts_enabled(regs) ? "n" : "ff",209209+ processor_modes[processor_mode(regs)],210210+ segment_eq(get_fs(), get_ds()) ? "kernel" : "user");211211+ {212212+ unsigned int ctrl;213213+214214+ buf[0] = '\0';215215+ {216216+ unsigned int transbase;217217+ asm("movc %0, p0.c2, #0\n"218218+ : "=r" (transbase));219219+ snprintf(buf, sizeof(buf), " Table: %08x", transbase);220220+ }221221+ asm("movc %0, p0.c1, #0\n" : "=r" (ctrl));222222+223223+ printk(KERN_DEFAULT "Control: %08x%s\n", ctrl, buf);224224+ }225225+}226226+227227+void show_regs(struct pt_regs *regs)228228+{229229+ printk(KERN_DEFAULT "\n");230230+ printk(KERN_DEFAULT "Pid: %d, comm: %20s\n",231231+ task_pid_nr(current), current->comm);232232+ __show_regs(regs);233233+ __backtrace();234234+}235235+236236+/*237237+ * Free current thread data structures etc..238238+ */239239+void exit_thread(void)240240+{241241+}242242+243243+void flush_thread(void)244244+{245245+ struct thread_info *thread = current_thread_info();246246+ struct task_struct *tsk = current;247247+248248+ memset(thread->used_cp, 0, sizeof(thread->used_cp));249249+ memset(&tsk->thread.debug, 0, sizeof(struct debug_info));250250+#ifdef CONFIG_UNICORE_FPU_F64251251+ memset(&thread->fpstate, 0, sizeof(struct fp_state));252252+#endif253253+}254254+255255+void release_thread(struct task_struct *dead_task)256256+{257257+}258258+259259+asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");260260+261261+int262262+copy_thread(unsigned long clone_flags, unsigned long stack_start,263263+ unsigned long stk_sz, struct task_struct *p, struct pt_regs *regs)264264+{265265+ struct thread_info *thread = task_thread_info(p);266266+ struct pt_regs *childregs = task_pt_regs(p);267267+268268+ *childregs = *regs;269269+ childregs->UCreg_00 = 0;270270+ childregs->UCreg_sp = stack_start;271271+272272+ memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));273273+ thread->cpu_context.sp = (unsigned long)childregs;274274+ thread->cpu_context.pc = (unsigned long)ret_from_fork;275275+276276+ if (clone_flags & CLONE_SETTLS)277277+ childregs->UCreg_16 = regs->UCreg_03;278278+279279+ return 0;280280+}281281+282282+/*283283+ * Fill in the task's elfregs structure for a core dump.284284+ */285285+int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs)286286+{287287+ elf_core_copy_regs(elfregs, task_pt_regs(t));288288+ return 1;289289+}290290+291291+/*292292+ * fill in the fpe structure for a core dump...293293+ */294294+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fp)295295+{296296+ struct thread_info *thread = current_thread_info();297297+ int used_math = thread->used_cp[1] | thread->used_cp[2];298298+299299+#ifdef CONFIG_UNICORE_FPU_F64300300+ if (used_math)301301+ memcpy(fp, &thread->fpstate, sizeof(*fp));302302+#endif303303+ return used_math != 0;304304+}305305+EXPORT_SYMBOL(dump_fpu);306306+307307+/*308308+ * Shuffle the argument into the correct register before calling the309309+ * thread function. r1 is the thread argument, r2 is the pointer to310310+ * the thread function, and r3 points to the exit function.311311+ */312312+asm(".pushsection .text\n"313313+" .align\n"314314+" .type kernel_thread_helper, #function\n"315315+"kernel_thread_helper:\n"316316+" mov.a asr, r7\n"317317+" mov r0, r4\n"318318+" mov lr, r6\n"319319+" mov pc, r5\n"320320+" .size kernel_thread_helper, . - kernel_thread_helper\n"321321+" .popsection");322322+323323+/*324324+ * Create a kernel thread.325325+ */326326+pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)327327+{328328+ struct pt_regs regs;329329+330330+ memset(®s, 0, sizeof(regs));331331+332332+ regs.UCreg_04 = (unsigned long)arg;333333+ regs.UCreg_05 = (unsigned long)fn;334334+ regs.UCreg_06 = (unsigned long)do_exit;335335+ regs.UCreg_07 = PRIV_MODE;336336+ regs.UCreg_pc = (unsigned long)kernel_thread_helper;337337+ regs.UCreg_asr = regs.UCreg_07 | PSR_I_BIT;338338+339339+ return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL);340340+}341341+EXPORT_SYMBOL(kernel_thread);342342+343343+unsigned long get_wchan(struct task_struct *p)344344+{345345+ struct stackframe frame;346346+ int count = 0;347347+ if (!p || p == current || p->state == TASK_RUNNING)348348+ return 0;349349+350350+ frame.fp = thread_saved_fp(p);351351+ frame.sp = thread_saved_sp(p);352352+ frame.lr = 0; /* recovered from the stack */353353+ frame.pc = thread_saved_pc(p);354354+ do {355355+ int ret = unwind_frame(&frame);356356+ if (ret < 0)357357+ return 0;358358+ if (!in_sched_functions(frame.pc))359359+ return frame.pc;360360+ } while ((count++) < 16);361361+ return 0;362362+}363363+364364+unsigned long arch_randomize_brk(struct mm_struct *mm)365365+{366366+ unsigned long range_end = mm->brk + 0x02000000;367367+ return randomize_range(mm->brk, range_end, 0) ? : mm->brk;368368+}369369+370370+/*371371+ * The vectors page is always readable from user space for the372372+ * atomic helpers and the signal restart code. Let's declare a mapping373373+ * for it so it is visible through ptrace and /proc/<pid>/mem.374374+ */375375+376376+int vectors_user_mapping(void)377377+{378378+ struct mm_struct *mm = current->mm;379379+ return install_special_mapping(mm, 0xffff0000, PAGE_SIZE,380380+ VM_READ | VM_EXEC |381381+ VM_MAYREAD | VM_MAYEXEC |382382+ VM_ALWAYSDUMP | VM_RESERVED,383383+ NULL);384384+}385385+386386+const char *arch_vma_name(struct vm_area_struct *vma)387387+{388388+ return (vma->vm_start == 0xffff0000) ? "[vectors]" : NULL;389389+}
+131
arch/unicore32/kernel/stacktrace.c
···11+/*22+ * linux/arch/unicore32/kernel/stacktrace.c33+ *44+ * Code specific to PKUnity SoC and UniCore ISA55+ *66+ * Copyright (C) 2001-2010 GUAN Xue-tao77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License version 2 as1010+ * published by the Free Software Foundation.1111+ */1212+#include <linux/module.h>1313+#include <linux/sched.h>1414+#include <linux/stacktrace.h>1515+1616+#include <asm/stacktrace.h>1717+1818+#if defined(CONFIG_FRAME_POINTER)1919+/*2020+ * Unwind the current stack frame and store the new register values in the2121+ * structure passed as argument. Unwinding is equivalent to a function return,2222+ * hence the new PC value rather than LR should be used for backtrace.2323+ *2424+ * With framepointer enabled, a simple function prologue looks like this:2525+ * mov ip, sp2626+ * stmdb sp!, {fp, ip, lr, pc}2727+ * sub fp, ip, #42828+ *2929+ * A simple function epilogue looks like this:3030+ * ldm sp, {fp, sp, pc}3131+ *3232+ * Note that with framepointer enabled, even the leaf functions have the same3333+ * prologue and epilogue, therefore we can ignore the LR value in this case.3434+ */3535+int notrace unwind_frame(struct stackframe *frame)3636+{3737+ unsigned long high, low;3838+ unsigned long fp = frame->fp;3939+4040+ /* only go to a higher address on the stack */4141+ low = frame->sp;4242+ high = ALIGN(low, THREAD_SIZE);4343+4444+ /* check current frame pointer is within bounds */4545+ if (fp < (low + 12) || fp + 4 >= high)4646+ return -EINVAL;4747+4848+ /* restore the registers from the stack frame */4949+ frame->fp = *(unsigned long *)(fp - 12);5050+ frame->sp = *(unsigned long *)(fp - 8);5151+ frame->pc = *(unsigned long *)(fp - 4);5252+5353+ return 0;5454+}5555+#endif5656+5757+void notrace walk_stackframe(struct stackframe *frame,5858+ int (*fn)(struct stackframe *, void *), void *data)5959+{6060+ while (1) {6161+ int ret;6262+6363+ if (fn(frame, data))6464+ break;6565+ ret = unwind_frame(frame);6666+ if (ret < 0)6767+ break;6868+ }6969+}7070+EXPORT_SYMBOL(walk_stackframe);7171+7272+#ifdef CONFIG_STACKTRACE7373+struct stack_trace_data {7474+ struct stack_trace *trace;7575+ unsigned int no_sched_functions;7676+ unsigned int skip;7777+};7878+7979+static int save_trace(struct stackframe *frame, void *d)8080+{8181+ struct stack_trace_data *data = d;8282+ struct stack_trace *trace = data->trace;8383+ unsigned long addr = frame->pc;8484+8585+ if (data->no_sched_functions && in_sched_functions(addr))8686+ return 0;8787+ if (data->skip) {8888+ data->skip--;8989+ return 0;9090+ }9191+9292+ trace->entries[trace->nr_entries++] = addr;9393+9494+ return trace->nr_entries >= trace->max_entries;9595+}9696+9797+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)9898+{9999+ struct stack_trace_data data;100100+ struct stackframe frame;101101+102102+ data.trace = trace;103103+ data.skip = trace->skip;104104+105105+ if (tsk != current) {106106+ data.no_sched_functions = 1;107107+ frame.fp = thread_saved_fp(tsk);108108+ frame.sp = thread_saved_sp(tsk);109109+ frame.lr = 0; /* recovered from the stack */110110+ frame.pc = thread_saved_pc(tsk);111111+ } else {112112+ register unsigned long current_sp asm("sp");113113+114114+ data.no_sched_functions = 0;115115+ frame.fp = (unsigned long)__builtin_frame_address(0);116116+ frame.sp = current_sp;117117+ frame.lr = (unsigned long)__builtin_return_address(0);118118+ frame.pc = (unsigned long)save_stack_trace_tsk;119119+ }120120+121121+ walk_stackframe(&frame, save_trace, &data);122122+ if (trace->nr_entries < trace->max_entries)123123+ trace->entries[trace->nr_entries++] = ULONG_MAX;124124+}125125+126126+void save_stack_trace(struct stack_trace *trace)127127+{128128+ save_stack_trace_tsk(current, trace);129129+}130130+EXPORT_SYMBOL_GPL(save_stack_trace);131131+#endif
+163
arch/unicore32/lib/backtrace.S
···11+/*22+ * linux/arch/unicore32/lib/backtrace.S33+ *44+ * Code specific to PKUnity SoC and UniCore ISA55+ *66+ * Copyright (C) 2001-2010 GUAN Xue-tao77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License version 2 as1010+ * published by the Free Software Foundation.1111+ */1212+#include <linux/linkage.h>1313+#include <asm/assembler.h>1414+ .text1515+1616+@ fp is 0 or stack frame1717+1818+#define frame v41919+#define sv_fp v52020+#define sv_pc v62121+#define offset v82222+2323+ENTRY(__backtrace)2424+ mov r0, fp2525+2626+ENTRY(c_backtrace)2727+2828+#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)2929+ mov pc, lr3030+ENDPROC(__backtrace)3131+ENDPROC(c_backtrace)3232+#else3333+ stm.w (v4 - v8, lr), [sp-] @ Save an extra register3434+ @ so we have a location...3535+ mov.a frame, r0 @ if frame pointer is zero3636+ beq no_frame @ we have no stack frames3737+3838+1: stm.w (pc), [sp-] @ calculate offset of PC stored3939+ ldw.w r0, [sp]+, #4 @ by stmfd for this CPU4040+ adr r1, 1b4141+ sub offset, r0, r14242+4343+/*4444+ * Stack frame layout:4545+ * optionally saved caller registers (r4 - r10)4646+ * saved fp4747+ * saved sp4848+ * saved lr4949+ * frame => saved pc5050+ * optionally saved arguments (r0 - r3)5151+ * saved sp => <next word>5252+ *5353+ * Functions start with the following code sequence:5454+ * mov ip, sp5555+ * stm.w (r0 - r3), [sp-] (optional)5656+ * corrected pc => stm.w sp, (..., fp, ip, lr, pc)5757+ */5858+for_each_frame:5959+6060+1001: ldw sv_pc, [frame+], #0 @ get saved pc6161+1002: ldw sv_fp, [frame+], #-12 @ get saved fp6262+6363+ sub sv_pc, sv_pc, offset @ Correct PC for prefetching6464+6565+1003: ldw r2, [sv_pc+], #-4 @ if stmfd sp, {args} exists,6666+ ldw r3, .Ldsi+4 @ adjust saved 'pc' back one6767+ cxor.a r3, r2 >> #14 @ instruction6868+ beq 201f6969+ sub r0, sv_pc, #4 @ allow for mov7070+ b 202f7171+201:7272+ sub r0, sv_pc, #8 @ allow for mov + stmia7373+202:7474+ ldw r1, [frame+], #-4 @ get saved lr7575+ mov r2, frame7676+ b.l dump_backtrace_entry7777+7878+ ldw r1, [sv_pc+], #-4 @ if stmfd sp, {args} exists,7979+ ldw r3, .Ldsi+48080+ cxor.a r3, r1 >> #148181+ bne 1004f8282+ ldw r0, [frame+], #-8 @ get sp8383+ sub r0, r0, #4 @ point at the last arg8484+ b.l .Ldumpstm @ dump saved registers8585+8686+1004: ldw r1, [sv_pc+], #0 @ if stmfd {, fp, ip, lr, pc}8787+ ldw r3, .Ldsi @ instruction exists,8888+ cxor.a r3, r1 >> #148989+ bne 201f9090+ sub r0, frame, #169191+ b.l .Ldumpstm @ dump saved registers9292+201:9393+ cxor.a sv_fp, #0 @ zero saved fp means9494+ beq no_frame @ no further frames9595+9696+ csub.a sv_fp, frame @ next frame must be9797+ mov frame, sv_fp @ above the current frame9898+ bua for_each_frame9999+100100+1006: adr r0, .Lbad101101+ mov r1, frame102102+ b.l printk103103+no_frame: ldm.w (v4 - v8, pc), [sp]+104104+ENDPROC(__backtrace)105105+ENDPROC(c_backtrace)106106+107107+ .pushsection __ex_table,"a"108108+ .align 3109109+ .long 1001b, 1006b110110+ .long 1002b, 1006b111111+ .long 1003b, 1006b112112+ .long 1004b, 1006b113113+ .popsection114114+115115+#define instr v4116116+#define reg v5117117+#define stack v6118118+119119+.Ldumpstm: stm.w (instr, reg, stack, v7, lr), [sp-]120120+ mov stack, r0121121+ mov instr, r1122122+ mov reg, #14123123+ mov v7, #0124124+1: mov r3, #1125125+ csub.a reg, #8126126+ bne 201f127127+ sub reg, reg, #3128128+201:129129+ cand.a instr, r3 << reg130130+ beq 2f131131+ add v7, v7, #1132132+ cxor.a v7, #6133133+ cmoveq v7, #1134134+ cmoveq r1, #'\n'135135+ cmovne r1, #' '136136+ ldw.w r3, [stack]+, #-4137137+ mov r2, reg138138+ csub.a r2, #8139139+ bsl 201f140140+ sub r2, r2, #3141141+201:142142+ cand.a instr, #0x40 @ if H is 1, high 16 regs143143+ beq 201f144144+ add r2, r2, #0x10 @ so r2 need add 16145145+201:146146+ adr r0, .Lfp147147+ b.l printk148148+2: sub.a reg, reg, #1149149+ bns 1b150150+ cxor.a v7, #0151151+ beq 201f152152+ adr r0, .Lcr153153+ b.l printk154154+201: ldm.w (instr, reg, stack, v7, pc), [sp]+155155+156156+.Lfp: .asciz "%cr%d:%08x"157157+.Lcr: .asciz "\n"158158+.Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n"159159+ .align160160+.Ldsi: .word 0x92eec000 >> 14 @ stm.w sp, (... fp, ip, lr, pc)161161+ .word 0x92e10000 >> 14 @ stm.w sp, ()162162+163163+#endif