URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [or32/] [kernel/] [process.c] - Rev 1765
Compare with Previous | Blame | View Log
/* * linux/arch/or32/kernel/process.c * * or32 version * author(s): Matjaz Breskvar (phoenix@opencores.org) * * derived from cris, i386, m68k, ppc, sh ports. * * changes: * 18. 11. 2003: Matjaz Breskvar (phoenix@opencores.org) * initial port to or32 architecture * * This file handles the architecture-dependent parts of process handling.. * Based on m86k. */ #define __KERNEL_SYSCALLS__ #include <stdarg.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/user.h> #include <linux/a.out.h> #include <linux/elfcore.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/system.h> #include <asm/io.h> #include <asm/processor.h> #include <asm/spr_defs.h> #include <asm/or32-hf.h> #include <linux/smp.h> /* * Initial task structure. Make this a per-architecture thing, * because different architectures tend to have different * alignment requirements and potentially different initial * setup. */ static struct fs_struct init_fs = INIT_FS; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM(init_mm); struct task_struct *current_set[NR_CPUS] = {&init_task, }; union task_union __attribute((aligned(PAGE_SIZE))) init_task_union = { INIT_TASK(init_task_union.task) }; void show_regs(struct pt_regs *regs) { extern void show_registers(struct pt_regs *regs); show_registers(regs); #if 0 printk("CPU #: %d\n", smp_processor_id()); printk(" PC: %08lx SR: %08lx SP: %08lx\n", regs->pc, regs->sr, regs->sp); printk("GPR00: %08lx GPR01: %08lx GPR02: %08lx GPR03: %08lx\n", 0L, regs->sp, regs->gprs[0], regs->gprs[1]); printk("GPR04: %08lx GPR05: %08lx GPR06: %08lx GPR07: %08lx\n", regs->gprs[2], regs->gprs[3], regs->gprs[4], regs->gprs[5]); printk("GPR08: %08lx GPR09: %08lx GPR10: %08lx GPR11: %08lx\n", regs->gprs[6], regs->gprs[7], regs->gprs[8], regs->gprs[9]); printk("GPR12: %08lx GPR13: %08lx GPR14: %08lx GPR15: %08lx\n", regs->gprs[10], regs->gprs[11], regs->gprs[12], regs->gprs[13]); printk("GPR16: %08lx GPR17: %08lx GPR18: %08lx GPR19: %08lx\n", regs->gprs[14], regs->gprs[15], regs->gprs[16], regs->gprs[17]); printk("GPR20: %08lx GPR21: %08lx GPR22: %08lx GPR23: %08lx\n", regs->gprs[18], regs->gprs[19], regs->gprs[20], regs->gprs[21]); printk("GPR24: %08lx GPR25: %08lx GPR26: %08lx GPR27: %08lx\n", regs->gprs[22], regs->gprs[23], regs->gprs[24], regs->gprs[25]); printk("GPR28: %08lx GPR29: %08lx GPR30: %08lx GPR31: %08lx\n", regs->gprs[26], regs->gprs[27], regs->gprs[28], regs->gprs[29]); printk(" RES: %08lx oGPR3: %08lx dummy: %08lx\n", regs->result, regs->orig_gpr3, regs->dummy); printk("Process %s (pid: %d, stackpage=%08lx)\n", current->comm, current->pid, (unsigned long)current); #endif } /* * The idle loop on an or32.. */ asmlinkage int sys_idle(void) { if (current->pid != 0) return -EPERM; /* endless idle loop with no priority at all */ current->counter = -100; for (;;) { schedule(); } } void hard_reset_now(void) { printk("***HARD_RESET_NOW***\n"); __asm__("l.ori r31,r0,0x100;" "l.jr r31 ;" "l.nop ;"); } void machine_restart(void) { hard_reset_now(); } /* * Similar to machine_power_off, but don't shut off power. Add code * here to freeze the system for e.g. post-mortem debug purpose when * possible. This halt has nothing to do with the idle halt. */ void machine_halt(void) { printk("***MACHINE_HALT***\n"); __asm__("l.nop 1"); } /* If or when software power-off is implemented, add code here. */ void machine_power_off(void) { __asm__("l.nop 1"); } /* * Free current thread data structures etc.. */ void exit_thread(void) { } /* * When a process does an "exec", machine state like FPU and debug * registers need to be reset. This is a hook function for that. * Currently we don't have any such state to reset, so this is empty. */ void flush_thread(void) { } asmlinkage int sys_fork(int r3, int r4, int r5, int r6, int r7, struct pt_regs *regs) { unsigned long sp; /* * __PHX__ :: cleanup * * printk("fork: current 0x%x, ksp 0x%x\n", * current, &sp); */ return do_fork(SIGCHLD, regs->sp, regs, 0); } asmlinkage int sys_clone(int r3, int r4, int r5, int r6, int r7, struct pt_regs *regs) { unsigned long clone_flags = (unsigned long)r3; return do_fork(clone_flags, regs->sp, regs, 0); } asmlinkage int sys_vfork(int r3, int r4, int r5, int r6, int r7, struct pt_regs *regs) { return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gprs[1], regs, 0); } void release_thread(struct task_struct *dead_task) { } int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, unsigned long unused, struct task_struct *p, struct pt_regs *regs) { struct pt_regs *childregs, *kregs; extern void ret_from_fork(void); unsigned long sp = (unsigned long)p + sizeof(union task_union); unsigned long childframe; /* Copy registers */ sp -= sizeof(struct pt_regs); childregs = (struct pt_regs *) sp; *childregs = *regs; if ((childregs->sr & SPR_SR_SM) == 1) { /* for kernel thread, set `current' and stackptr in new task */ childregs->sp = sp + sizeof(struct pt_regs); childregs->gprs[0] = (unsigned long) p; /* __PHX__ :: i think this thread.regs is not needed */ p->thread.regs = NULL; /* no user register state */ } else p->thread.regs = childregs; childregs->gprs[9] = 0; /* Result from fork() */ // sp -= STACK_FRAME_OVERHEAD; childframe = sp; /* * The way this works is that at some point in the future * some task will call _switch to switch to the new task. * That will pop off the stack frame created below and start * the new task running at ret_from_fork. The new task will * do some house keeping and then return from the fork or clone * system call, using the stack frame created above. */ sp -= sizeof(struct pt_regs); kregs = (struct pt_regs *) sp; // sp -= STACK_FRAME_OVERHEAD; p->thread.ksp = sp; kregs->sr = regs->sr | SPR_SR_SM; kregs->sp = sp + sizeof(struct pt_regs); kregs->gprs[0] = p; /* current */ kregs->gprs[1] = p; /* for schedule_tail */ kregs->pc = (unsigned long)ret_from_fork; p->thread.last_syscall = -1; return 0; } /* * Set up a thread for executing a new program */ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) { phx_warn("NIP: %x, SP: %x", pc, sp); set_fs(USER_DS); memset(regs->gprs, 0, sizeof(regs->gprs)); regs->pc = pc; regs->sr = regs->sr & ~ SPR_SR_SM; regs->sp = sp; } /* Fill in the fpu structure for a core dump. */ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) { phx_warn("TODO"); /* __PHX__: __TODO__ for FPU */ return 0; } void _switch_to(struct task_struct *prev, struct task_struct *new, struct task_struct **last) { struct thread_struct *new_thread, *old_thread; long flags; save_flags(flags); cli(); check_stack(NULL, __FILE__, __FUNCTION__, __LINE__); /* current_set is an array of saved current pointers * (one for each cpu). we need them at user->kernel transition, * while we save them at kernel->user transition */ new_thread = &new->thread; old_thread = ¤t->thread; current_set[smp_processor_id()] = new; *last = _switch(old_thread, new_thread); check_stack(NULL, __FILE__, __FUNCTION__, __LINE__); restore_flags(flags); } /* * fill in the user structure for a core dump.. */ void dump_thread(struct pt_regs *regs, struct user *dump) { phx_warn("TODO"); /* changed the size calculations - should hopefully work better. lbt */ dump->magic = CMAGIC; dump->start_code = 0; dump->start_stack = regs->sp & ~(PAGE_SIZE - 1); dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT; dump->u_dsize -= dump->u_tsize; dump->u_ssize = 0; /* __PHX__: FIXME !! i've just commented out this for now */ // dump->u_ar0 = (struct pt_regs *)(((int)(&dump->regs)) -((int)(dump))); dump->regs = *regs; /* dump floating point stuff */ /* __PHX__: __TODO__ FPU * dump->u_fpvalid = dump_fpu (regs, &dump->or32fp); */ } /* * sys_execve() executes a new program. */ asmlinkage int sys_execve(char *name, char **argv, char **envp, int r6, int r7, struct pt_regs *regs) { int error; char * filename; filename = getname(name); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; error = do_execve(filename, argv, envp, regs); if (error == 0) { current->ptrace &= ~PT_DTRACE; } putname(filename); out: return error; } unsigned long get_wchan(struct task_struct *p) { /* __PHX__: TODO */ phx_warn("TODO"); return 0; }