Commit f73670e8a55c11d47c28dca35dc4bc7dfbd4e6eb

Authored by GuanXuetao
1 parent 141c943fd4

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>

Showing 6 changed files with 912 additions and 0 deletions Side-by-side Diff

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__ */
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__ */
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);
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 +}
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
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