linux/arch/unicore32/kernel/process.c
<<
>>
Prefs
   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
  42static 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 */
  54void 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
  73static char reboot_mode = 'h';
  74
  75int __init reboot_setup(char *str)
  76{
  77        reboot_mode = str[0];
  78        return 1;
  79}
  80
  81__setup("reboot=", reboot_setup);
  82
  83void machine_halt(void)
  84{
  85        gpio_set_value(GPO_SOFT_OFF, 0);
  86}
  87
  88/*
  89 * Function pointers to optional machine specific functions
  90 */
  91void (*pm_power_off)(void) = NULL;
  92
  93void machine_power_off(void)
  94{
  95        if (pm_power_off)
  96                pm_power_off();
  97        machine_halt();
  98}
  99
 100void 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                writel(0x00002001, PM_PLLSYSCFG); /* cpu clk = 250M */
 129                writel(0x00100800, PM_PLLDDRCFG); /* ddr clk =  44M */
 130                writel(0x00002001, PM_PLLVGACFG); /* 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" (PM_PMCR),
 145                          "r" (PM_PMCR_CFBSYS | PM_PMCR_CFBDDR
 146                                | PM_PMCR_CFBVGA),
 147                          "r" (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
 161void __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
 227void 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 */
 239void exit_thread(void)
 240{
 241}
 242
 243void 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
 255void release_thread(struct task_struct *dead_task)
 256{
 257}
 258
 259asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 260
 261int
 262copy_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 */
 285int 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 */
 294int 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}
 305EXPORT_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 */
 312asm(".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 */
 326pid_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}
 341EXPORT_SYMBOL(kernel_thread);
 342
 343unsigned 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
 364unsigned 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
 376int 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
 386const char *arch_vma_name(struct vm_area_struct *vma)
 387{
 388        return (vma->vm_start == 0xffff0000) ? "[vectors]" : NULL;
 389}
 390