process.c 4.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/*
 *  Copyright (C) 2000-2003  Axis Communications AB
 *
 *  Authors:   Bjorn Wesen (bjornw@axis.com)
 *             Mikael Starvik (starvik@axis.com)
 *             Tobias Anderberg (tobiasa@axis.com), CRISv32 port.
 *
 * This file handles the architecture-dependent parts of process handling..
 */

#include <linux/sched.h>
12
#include <linux/slab.h>
13 14
#include <linux/err.h>
#include <linux/fs.h>
15 16 17 18
#include <hwregs/reg_rdwr.h>
#include <hwregs/reg_map.h>
#include <hwregs/timer_defs.h>
#include <hwregs/intr_vect_defs.h>
A
Al Viro 已提交
19
#include <linux/ptrace.h>
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81

extern void stop_watchdog(void);

extern int cris_hlt_counter;

/* We use this if we don't have any better idle routine. */
void default_idle(void)
{
	local_irq_disable();
	if (!need_resched() && !cris_hlt_counter) {
	        /* Halt until exception. */
		__asm__ volatile("ei    \n\t"
                                 "halt      ");
	}
	local_irq_enable();
}

/*
 * Free current thread data structures etc..
 */

extern void deconfigure_bp(long pid);
void exit_thread(void)
{
	deconfigure_bp(current->pid);
}

/*
 * If the watchdog is enabled, disable interrupts and enter an infinite loop.
 * The watchdog will reset the CPU after 0.1s. If the watchdog isn't enabled
 * then enable it and wait.
 */
extern void arch_enable_nmi(void);

void
hard_reset_now(void)
{
	/*
	 * Don't declare this variable elsewhere.  We don't want any other
	 * code to know about it than the watchdog handler in entry.S and
	 * this code, implementing hard reset through the watchdog.
	 */
#if defined(CONFIG_ETRAX_WATCHDOG)
	extern int cause_of_death;
#endif

	printk("*** HARD RESET ***\n");
	local_irq_disable();

#if defined(CONFIG_ETRAX_WATCHDOG)
	cause_of_death = 0xbedead;
#else
{
	reg_timer_rw_wd_ctrl wd_ctrl = {0};

	stop_watchdog();

	wd_ctrl.key = 16;	/* Arbitrary key. */
	wd_ctrl.cnt = 1;	/* Minimum time. */
	wd_ctrl.cmd = regk_timer_start;

        arch_enable_nmi();
82
	REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl);
83 84 85 86 87 88 89 90 91 92 93 94
}
#endif

	while (1)
		; /* Wait for reset. */
}

/*
 * Return saved PC of a blocked thread.
 */
unsigned long thread_saved_pc(struct task_struct *t)
{
A
Al Viro 已提交
95
	return task_pt_regs(t)->erp;
96 97 98 99 100 101 102 103 104 105 106 107
}

/*
 * Setup the child's kernel stack with a pt_regs and call switch_stack() on it.
 * It will be unnested during _resume and _ret_from_sys_call when the new thread
 * is scheduled.
 *
 * Also setup the thread switching structure which is used to keep
 * thread-specific data during _resumes.
 */

extern asmlinkage void ret_from_fork(void);
A
Al Viro 已提交
108
extern asmlinkage void ret_from_kernel_thread(void);
109 110

int
A
Alexey Dobriyan 已提交
111
copy_thread(unsigned long clone_flags, unsigned long usp,
A
Al Viro 已提交
112
	unsigned long arg,
A
Al Viro 已提交
113
	struct task_struct *p, struct pt_regs *unused)
114
{
A
Al Viro 已提交
115 116
	struct pt_regs *childregs = task_pt_regs(p);
	struct switch_stack *swstack = ((struct switch_stack *) childregs) - 1;
117 118 119 120 121 122

	/*
	 * Put the pt_regs structure at the end of the new kernel stack page and
	 * fix it up. Note: the task_struct doubles as the kernel stack for the
	 * task.
	 */
A
Al Viro 已提交
123 124 125 126 127 128 129 130 131 132 133
	if (unlikely(p->flags & PF_KTHREAD)) {
		memset(swstack, 0,
			sizeof(struct switch_stack) + sizeof(struct pt_regs));
		swstack->r1 = usp;
		swstack->r2 = arg;
		childregs->ccs = 1 << (I_CCS_BITNR + CCS_SHIFT);
		swstack->return_ip = (unsigned long) ret_from_kernel_thread;
		p->thread.ksp = (unsigned long) swstack;
		p->thread.usp = 0;
		return 0;
	}
A
Al Viro 已提交
134
	*childregs = *current_pt_regs();	/* Struct copy of pt_regs. */
135 136 137
        childregs->r10 = 0;	/* Child returns 0 after a fork/clone. */

	/* Set a new TLS ?
L
Lucas De Marchi 已提交
138
	 * The TLS is in $mof because it is the 5th argument to sys_clone.
139 140
	 */
	if (p->mm && (clone_flags & CLONE_SETTLS)) {
A
Al Viro 已提交
141
		task_thread_info(p)->tls = childregs->mof;
142 143 144 145
	}

	/* Put the switch stack right below the pt_regs. */

S
Simon Arlott 已提交
146
	/* Parameter to ret_from_sys_call. 0 is don't restart the syscall. */
147 148 149 150 151 152 153 154 155
	swstack->r9 = 0;

	/*
	 * We want to return into ret_from_sys_call after the _resume.
	 * ret_from_fork will call ret_from_sys_call.
	 */
	swstack->return_ip = (unsigned long) ret_from_fork;

	/* Fix the user-mode and kernel-mode stackpointer. */
A
Al Viro 已提交
156
	p->thread.usp = usp ?: rdusp();
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
	p->thread.ksp = (unsigned long) swstack;

	return 0;
}

unsigned long
get_wchan(struct task_struct *p)
{
	/* TODO */
	return 0;
}
#undef last_sched
#undef first_sched

void show_regs(struct pt_regs * regs)
{
	unsigned long usp = rdusp();
        printk("ERP: %08lx SRP: %08lx  CCS: %08lx USP: %08lx MOF: %08lx\n",
		regs->erp, regs->srp, regs->ccs, usp, regs->mof);

	printk(" r0: %08lx  r1: %08lx   r2: %08lx  r3: %08lx\n",
		regs->r0, regs->r1, regs->r2, regs->r3);

	printk(" r4: %08lx  r5: %08lx   r6: %08lx  r7: %08lx\n",
		regs->r4, regs->r5, regs->r6, regs->r7);

	printk(" r8: %08lx  r9: %08lx  r10: %08lx r11: %08lx\n",
		regs->r8, regs->r9, regs->r10, regs->r11);

	printk("r12: %08lx r13: %08lx oR10: %08lx\n",
		regs->r12, regs->r13, regs->orig_r10);
}