OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [or32/] [kernel/] [process.c] - Rev 1306

Go to most recent revision | 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 = &current->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;
}
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.