Root/target/linux/ubicom32/files/arch/ubicom32/kernel/process.c

1/*
2 * arch/ubicom32/kernel/process.c
3 * Ubicom32 architecture-dependent process handling.
4 *
5 * (C) Copyright 2009, Ubicom, Inc.
6 * Copyright (C) 1995 Hamish Macdonald
7 *
8 * 68060 fixes by Jesper Skov
9 *
10 * uClinux changes
11 * Copyright (C) 2000-2002, David McCullough <davidm@snapgear.com>
12 *
13 * This file is part of the Ubicom32 Linux Kernel Port.
14 *
15 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
16 * it and/or modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation, either version 2 of the
18 * License, or (at your option) any later version.
19 *
20 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
21 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
22 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
23 * the GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with the Ubicom32 Linux Kernel Port. If not,
27 * see <http://www.gnu.org/licenses/>.
28 *
29 * Ubicom32 implementation derived from (with many thanks):
30 * arch/m68knommu
31 * arch/blackfin
32 * arch/parisc
33 */
34
35/*
36 * This file handles the architecture-dependent parts of process handling..
37 */
38
39#include <linux/module.h>
40#include <linux/errno.h>
41#include <linux/sched.h>
42#include <linux/kernel.h>
43#include <linux/mm.h>
44#include <linux/smp.h>
45#include <linux/smp_lock.h>
46#include <linux/stddef.h>
47#include <linux/unistd.h>
48#include <linux/ptrace.h>
49#include <linux/slab.h>
50#include <linux/user.h>
51#include <linux/a.out.h>
52#include <linux/interrupt.h>
53#include <linux/reboot.h>
54#include <linux/fs.h>
55#include <linux/pm.h>
56
57#include <linux/uaccess.h>
58#include <asm/system.h>
59#include <asm/traps.h>
60#include <asm/machdep.h>
61#include <asm/setup.h>
62#include <asm/pgtable.h>
63#include <asm/ip5000.h>
64#include <asm/range-protect.h>
65
66#define DUMP_RANGE_REGISTER(REG, IDX) asm volatile ( \
67        " move.4 %0, "REG"_RANGE"IDX"_EN \n\t" \
68        " move.4 %1, "REG"_RANGE"IDX"_LO \n\t" \
69        " move.4 %2, "REG"_RANGE"IDX"_HI \n\t" \
70                : "=d"(en), "=d"(lo), "=d"(hi) \
71        ); \
72        printk(KERN_NOTICE REG"Range"IDX": en:%08x, range: %08x-%08x\n", \
73                (unsigned int)en, \
74                (unsigned int)lo, \
75                (unsigned int)hi)
76
77asmlinkage void ret_from_fork(void);
78
79void (*pm_power_off)(void) = machine_power_off;
80EXPORT_SYMBOL(pm_power_off);
81
82/* machine-dependent / hardware-specific power functions */
83void (*mach_reset)(void);
84void (*mach_halt)(void);
85void (*mach_power_off)(void);
86
87/*
88 * cpu_idle()
89 * The idle thread.
90 *
91 * Our idle loop suspends and is woken up by a timer interrupt.
92 */
93void cpu_idle(void)
94{
95    while (1) {
96        local_irq_disable();
97        while (!need_resched()) {
98            local_irq_enable();
99            thread_suspend();
100            local_irq_disable();
101        }
102        local_irq_enable();
103        preempt_enable_no_resched();
104        schedule();
105        preempt_disable();
106    }
107}
108
109/*
110 * dump_fpu()
111 *
112 * Fill in the fpu structure for a core dump. (just a stub as we don't have
113 * an fpu)
114 */
115int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpregs)
116{
117    return 1;
118}
119
120/*
121 * machine_restart()
122 * Resets the system.
123 */
124void machine_restart(char *__unused)
125{
126    /*
127     * Disable all threads except myself. We can do this
128     * directly without needing to call smp_send_stop
129     * because we have a unique architecture where
130     * one thread can disable one or more other threads.
131     */
132    thread_disable_others();
133
134    /*
135     * Call the hardware-specific machine reset function.
136     */
137    if (mach_reset) {
138        mach_reset();
139    }
140
141    printk(KERN_EMERG "System Restarting\n");
142
143    /*
144     * Set watchdog to trigger (after 1ms delay) (12 Mhz is the fixed OSC)
145     */
146    UBICOM32_IO_TIMER->tkey = TIMER_TKEYVAL;
147    UBICOM32_IO_TIMER->wdcom = UBICOM32_IO_TIMER->mptval +
148        (12000000 / 1000);
149    UBICOM32_IO_TIMER->wdcfg = 0;
150    UBICOM32_IO_TIMER->tkey = 0;
151
152    /*
153     * Wait for watchdog
154     */
155    asm volatile (
156        " move.4 MT_EN, #0 \n\t"
157        " pipe_flush 0 \n\t"
158    );
159
160    local_irq_disable();
161    for (;;) {
162        thread_suspend();
163    }
164}
165
166/*
167 * machine_halt()
168 * Halt the machine.
169 *
170 * Similar to machine_power_off, but don't shut off power. Add code
171 * here to freeze the system for e.g. post-mortem debug purpose when
172 * possible. This halt has nothing to do with the idle halt.
173 */
174void machine_halt(void)
175{
176    /*
177     * Disable all threads except myself. We can do this
178     * directly without needing to call smp_send_stop
179     * because we have a unique architecture where
180     * one thread can disable one or more other threads.
181     */
182    thread_disable_others();
183
184    /*
185     * Call the hardware-specific machine halt function.
186     */
187    if (mach_halt) {
188        mach_halt();
189    }
190
191    printk(KERN_EMERG "System Halted, OK to turn off power\n");
192    local_irq_disable();
193    for (;;) {
194        thread_suspend();
195    }
196}
197
198/*
199 * machine_power_off()
200 * Turn the power off, if a power off handler is defined, otherwise, spin
201 * endlessly.
202 */
203void machine_power_off(void)
204{
205    /*
206     * Disable all threads except myself. We can do this
207     * directly without needing to call smp_send_stop
208     * because we have a unique architecture where
209     * one thread can disable one or more other threads.
210     */
211    thread_disable_others();
212
213    /*
214     * Call the hardware-specific machine power off function.
215     */
216    if (mach_power_off) {
217        mach_power_off();
218    }
219
220    printk(KERN_EMERG "System Halted, OK to turn off power\n");
221    local_irq_disable();
222    for (;;) {
223        thread_suspend();
224    }
225}
226
227/*
228 * address_is_valid()
229 * check if an address is valid -- (for read access)
230 */
231static bool address_is_valid(const void *address)
232{
233    int addr = (int)address;
234    unsigned long socm, eocm, sdram, edram;
235
236    if (addr & 3)
237        return false;
238
239    processor_ocm(&socm, &eocm);
240    processor_dram(&sdram, &edram);
241    if (addr >= socm && addr < eocm)
242        return true;
243
244    if (addr >= sdram && addr < edram)
245        return true;
246
247    return false;
248}
249
250/*
251 * vma_path_name_is_valid()
252 * check if path_name of a vma is a valid string
253 */
254static bool vma_path_name_is_valid(const char *str)
255{
256#define MAX_NAME_LEN 256
257    int i = 0;
258    if (!address_is_valid(str))
259        return false;
260
261    for (; i < MAX_NAME_LEN; i++, str++) {
262        if (*str == '\0')
263            return true;
264    }
265
266    return false;
267}
268
269/*
270 * show_vmas()
271 * show vma info of a process
272 */
273void show_vmas(struct task_struct *task)
274{
275#ifdef CONFIG_DEBUG_VERBOSE
276#define UBICOM32_MAX_VMA_COUNT 1024
277
278    struct vm_area_struct *vma;
279    struct file *file;
280    char *name = "";
281    int flags, loop = 0;
282
283    printk(KERN_NOTICE "Start of vma list\n");
284
285    if (!address_is_valid(task) || !address_is_valid(task->mm))
286        goto error;
287
288    vma = task->mm->mmap;
289    while (vma) {
290        if (!address_is_valid(vma))
291            goto error;
292
293        flags = vma->vm_flags;
294        file = vma->vm_file;
295
296        if (file) {
297            /* seems better to use dentry op here, but sanity check is easier this way */
298            if (!address_is_valid(file) || !address_is_valid(file->f_path.dentry) || !vma_path_name_is_valid(file->f_path.dentry->d_name.name))
299                goto error;
300
301            name = (char *)file->f_path.dentry->d_name.name;
302        }
303
304        /* Similar to /proc/pid/maps format */
305        printk(KERN_NOTICE "%08lx-%08lx %c%c%c%c %08lx %s\n",
306            vma->vm_start,
307            vma->vm_end,
308            flags & VM_READ ? 'r' : '-',
309            flags & VM_WRITE ? 'w' : '-',
310            flags & VM_EXEC ? 'x' : '-',
311            flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',
312            vma->vm_pgoff << PAGE_SHIFT,
313            name);
314
315        vma = vma->vm_next;
316
317        if (loop++ > UBICOM32_MAX_VMA_COUNT)
318            goto error;
319    }
320
321    printk(KERN_NOTICE "End of vma list\n");
322    return;
323
324error:
325    printk(KERN_NOTICE "\nCorrupted vma list, abort!\n");
326#endif
327}
328
329/*
330 * show_regs()
331 * Print out all of the registers.
332 */
333void show_regs(struct pt_regs *regs)
334{
335    unsigned int i;
336    unsigned int en, lo, hi;
337
338    printk(KERN_NOTICE "regs: %p, tid: %d\n",
339        (void *)regs,
340        thread_get_self());
341
342    printk(KERN_NOTICE "pc: %08x, previous_pc: %08x\n\n",
343        (unsigned int)regs->pc,
344        (unsigned int)regs->previous_pc);
345
346    printk(KERN_NOTICE "Data registers\n");
347    for (i = 0; i < 16; i++) {
348        printk("D%02d: %08x, ", i, (unsigned int)regs->dn[i]);
349        if ((i % 4) == 3) {
350            printk("\n");
351        }
352    }
353    printk("\n");
354
355    printk(KERN_NOTICE "Address registers\n");
356    for (i = 0; i < 8; i++) {
357        printk("A%02d: %08x, ", i, (unsigned int)regs->an[i]);
358        if ((i % 4) == 3) {
359            printk("\n");
360        }
361    }
362    printk("\n");
363
364    printk(KERN_NOTICE "acc0: %08x-%08x, acc1: %08x-%08x\n",
365        (unsigned int)regs->acc0[1],
366        (unsigned int)regs->acc0[0],
367        (unsigned int)regs->acc1[1],
368        (unsigned int)regs->acc1[0]);
369
370    printk(KERN_NOTICE "mac_rc16: %08x, source3: %08x\n",
371        (unsigned int)regs->mac_rc16,
372        (unsigned int)regs->source3);
373
374    printk(KERN_NOTICE "inst_cnt: %08x, csr: %08x\n",
375        (unsigned int)regs->inst_cnt,
376        (unsigned int)regs->csr);
377
378    printk(KERN_NOTICE "int_mask0: %08x, int_mask1: %08x\n",
379        (unsigned int)regs->int_mask0,
380        (unsigned int)regs->int_mask1);
381
382    /*
383     * Dump range registers
384     */
385    DUMP_RANGE_REGISTER("I", "0");
386    DUMP_RANGE_REGISTER("I", "1");
387    DUMP_RANGE_REGISTER("I", "2");
388    DUMP_RANGE_REGISTER("I", "3");
389    DUMP_RANGE_REGISTER("D", "0");
390    DUMP_RANGE_REGISTER("D", "1");
391    DUMP_RANGE_REGISTER("D", "2");
392    DUMP_RANGE_REGISTER("D", "3");
393    DUMP_RANGE_REGISTER("D", "4");
394
395    printk(KERN_NOTICE "frame_type: %d, nesting_level: %d, thread_type %d\n\n",
396        (int)regs->frame_type,
397        (int)regs->nesting_level,
398        (int)regs->thread_type);
399}
400
401/*
402 * kernel_thread_helper()
403 * On execution d0 will be 0, d1 will be the argument to be passed to the
404 * kernel function. d2 contains the kernel function that needs to get
405 * called. d3 will contain address to do_exit which need to get moved
406 * into a5. On return from fork the child thread d0 will be 0. We call
407 * this dummy function which in turn loads the argument
408 */
409asmlinkage void kernel_thread_helper(void);
410
411/*
412 * kernel_thread()
413 * Create a kernel thread
414 */
415int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
416{
417    struct pt_regs regs;
418
419    memset(&regs, 0, sizeof(regs));
420
421    regs.dn[1] = (unsigned long)arg;
422    regs.dn[2] = (unsigned long)fn;
423    regs.dn[3] = (unsigned long)do_exit;
424    regs.an[5] = (unsigned long)kernel_thread_helper;
425    regs.pc = (unsigned long)kernel_thread_helper;
426    regs.nesting_level = 0;
427    regs.thread_type = KERNEL_THREAD;
428
429    return do_fork(flags | CLONE_VM | CLONE_UNTRACED,
430               0, &regs, 0, NULL, NULL);
431}
432EXPORT_SYMBOL(kernel_thread);
433
434/*
435 * flush_thread()
436 * XXX todo
437 */
438void flush_thread(void)
439{
440    /* XXX todo */
441}
442
443/*
444 * sys_fork()
445 * Not implemented on no-mmu.
446 */
447asmlinkage int sys_fork(struct pt_regs *regs)
448{
449    /* fork almost works, enough to trick you into looking elsewhere :-( */
450    return -EINVAL;
451}
452
453/*
454 * sys_vfork()
455 * By the time we get here, the non-volatile registers have also been saved
456 * on the stack. We do some ugly pointer stuff here.. (see also copy_thread
457 * which does context copy).
458 */
459asmlinkage int sys_vfork(struct pt_regs *regs)
460{
461    unsigned long old_sp = regs->an[7];
462    unsigned long old_a5 = regs->an[5];
463    unsigned long old_return_address;
464    long do_fork_return;
465
466    /*
467     * Read the old retrun address from the stack.
468     */
469    if (copy_from_user(&old_return_address,
470               (void *)old_sp, sizeof(unsigned long))) {
471        force_sig(SIGSEGV, current);
472        return 0;
473    }
474
475    /*
476     * Pop the vfork call frame by setting a5 and pc to the old_return
477     * address and incrementing the stack pointer by 4.
478     */
479    regs->an[5] = old_return_address;
480    regs->pc = old_return_address;
481    regs->an[7] += 4;
482
483    do_fork_return = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
484                 regs->an[7], regs, 0, NULL, NULL);
485
486    /*
487     * Now we have to test if the return code is an error. If it is an error
488     * then restore the frame and we will execute error processing in user
489     * space. Other wise the child and the parent will return to the correct
490     * places.
491     */
492    if ((unsigned long)(do_fork_return) >= (unsigned long)(-125)) {
493        /*
494         * Error case. We need to restore the frame.
495         */
496        regs->an[5] = old_a5;
497        regs->pc = old_a5;
498        regs->an[7] = old_sp;
499    }
500
501    return do_fork_return;
502}
503
504/*
505 * sys_clone()
506 * creates a child thread.
507 */
508asmlinkage int sys_clone(unsigned long clone_flags,
509             unsigned long newsp,
510             struct pt_regs *regs)
511{
512    if (!newsp)
513        newsp = regs->an[7];
514    return do_fork(clone_flags, newsp, regs, 0,
515               NULL, NULL);
516}
517
518/*
519 * copy_thread()
520 * low level thread copy, only used by do_fork in kernel/fork.c
521 */
522int copy_thread(unsigned long clone_flags,
523        unsigned long usp, unsigned long topstk,
524        struct task_struct *p, struct pt_regs *regs)
525
526{
527    struct pt_regs *childregs;
528
529    childregs = (struct pt_regs *)
530        (task_stack_page(p) + THREAD_SIZE - 8) - 1;
531
532    *childregs = *regs;
533
534    /*
535     * Set return value for child to be 0.
536     */
537    childregs->dn[0] = 0;
538
539    if (usp)
540        childregs->an[7] = usp;
541    else
542        childregs->an[7] = (unsigned long)task_stack_page(p) +
543            THREAD_SIZE - 8;
544
545    /*
546     * Set up the switch_to frame to return to "ret_from_fork"
547     */
548    p->thread.a5 = (unsigned long)ret_from_fork;
549    p->thread.sp = (unsigned long)childregs;
550
551    return 0;
552}
553
554/*
555 * sys_execve()
556 * executes a new program.
557 */
558asmlinkage int sys_execve(char *name, char **argv,
559              char **envp, struct pt_regs *regs)
560{
561    int error;
562    char *filename;
563
564    lock_kernel();
565    filename = getname(name);
566    error = PTR_ERR(filename);
567    if (IS_ERR(filename))
568        goto out;
569    error = do_execve(filename, argv, envp, regs);
570    putname(filename);
571    asm (" .global sys_execve_complete\n"
572         " sys_execve_complete:");
573out:
574    unlock_kernel();
575    return error;
576}
577
578/*
579 * Return saved PC of a blocked thread.
580 */
581unsigned long thread_saved_pc(struct task_struct *tsk)
582{
583    return tsk->thread.a5;
584}
585
586
587unsigned long get_wchan(struct task_struct *p)
588{
589    unsigned long pc;
590
591    /*
592     * If we don't have a process, or it is not the current
593     * one or not RUNNING, it makes no sense to ask for a
594     * wchan.
595     */
596    if (!p || p == current || p->state == TASK_RUNNING)
597        return 0;
598
599    /*
600     * TODO: If the process is in the middle of schedule, we
601     * are supposed to do something different but for now we
602     * will return the same thing in both situations.
603     */
604    pc = thread_saved_pc(p);
605    if (in_sched_functions(pc))
606        return pc;
607    return pc;
608}
609
610
611/*
612 * Infrequently used interface to dump task registers to core files.
613 */
614int dump_task_regs(struct task_struct *task, elf_gregset_t *elfregs)
615{
616    struct pt_regs *regs = task_pt_regs(task);
617    *(struct pt_regs *)elfregs = *regs;
618
619    return 1;
620}
621
622/*
623 * __switch_to is the function that implements the contex save and
624 * switch within the kernel. Since this is a function call very few
625 * registers have to be saved to pull this off. d0 holds prev and we
626 * want to preserve it. prev_switch is a pointer to task->thread
627 * structure. This is where we will save the register state. next_switch
628 * is pointer to the next task's thread structure that holds the
629 * registers.
630 */
631asmlinkage void *__switch_to(struct task_struct *prev,
632                 struct thread_struct *prev_switch,
633                 struct thread_struct *next_switch)
634    __attribute__((naked));
635

Archive Download this file



interactive