process.c 5.3 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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
/*
 *  linux/arch/h8300/kernel/process.c
 *
 * Yoshinori Sato <ysato@users.sourceforge.jp>
 *
 *  Based on:
 *
 *  linux/arch/m68knommu/kernel/process.c
 *
 *  Copyright (C) 1998  D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>,
 *                      Kenneth Albanowski <kjahds@kjahds.com>,
 *                      The Silver Hammer Group, Ltd.
 *
 *  linux/arch/m68k/kernel/process.c
 *
 *  Copyright (C) 1995  Hamish Macdonald
 *
 *  68060 fixes by Jesper Skov
 */

/*
 * This file handles the architecture-dependent parts of process handling..
 */

#include <linux/config.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.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/interrupt.h>
#include <linux/reboot.h>

#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/traps.h>
#include <asm/setup.h>
#include <asm/pgtable.h>

A
Adrian Bunk 已提交
48 49 50
void (*pm_power_off)(void) = NULL;
EXPORT_SYMBOL(pm_power_off);

L
Linus Torvalds 已提交
51 52 53 54 55 56
asmlinkage void ret_from_fork(void);

/*
 * The idle loop on an H8/300..
 */
#if !defined(CONFIG_H8300H_SIM) && !defined(CONFIG_H8S_SIM)
57
static void default_idle(void)
L
Linus Torvalds 已提交
58
{
59 60 61 62 63 64 65
	local_irq_disable();
	if (!need_resched()) {
		local_irq_enable();
		/* XXX: race here! What if need_resched() gets set now? */
		__asm__("sleep");
	} else
		local_irq_enable();
L
Linus Torvalds 已提交
66 67
}
#else
68
static void default_idle(void)
L
Linus Torvalds 已提交
69
{
70
	cpu_relax();
L
Linus Torvalds 已提交
71 72 73 74 75 76 77 78 79 80 81 82
}
#endif
void (*idle)(void) = default_idle;

/*
 * The idle thread. There's no useful work to be
 * done, so just try to conserve power and have a
 * low exit latency (ie sit in a loop waiting for
 * somebody to say that they'd like to reschedule)
 */
void cpu_idle(void)
{
83 84 85 86 87 88 89
	while (1) {
		while (!need_resched())
			idle();
		preempt_enable_no_resched();
		schedule();
		preempt_disable();
	}
L
Linus Torvalds 已提交
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 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 189 190 191 192 193 194 195 196 197 198 199 200
}

void machine_restart(char * __unused)
{
	local_irq_disable();
	__asm__("jmp @@0"); 
}

void machine_halt(void)
{
	local_irq_disable();
	__asm__("sleep");
	for (;;);
}

void machine_power_off(void)
{
	local_irq_disable();
	__asm__("sleep");
	for (;;);
}

void show_regs(struct pt_regs * regs)
{
	printk("\nPC: %08lx  Status: %02x",
	       regs->pc, regs->ccr);
	printk("\nORIG_ER0: %08lx ER0: %08lx ER1: %08lx",
	       regs->orig_er0, regs->er0, regs->er1);
	printk("\nER2: %08lx ER3: %08lx ER4: %08lx ER5: %08lx",
	       regs->er2, regs->er3, regs->er4, regs->er5);
	printk("\nER6' %08lx ",regs->er6);
	if (user_mode(regs))
		printk("USP: %08lx\n", rdusp());
	else
		printk("\n");
}

/*
 * Create a kernel thread
 */
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
	long retval;
	long clone_arg;
	mm_segment_t fs;

	fs = get_fs();
	set_fs (KERNEL_DS);
	clone_arg = flags | CLONE_VM;
	__asm__("mov.l sp,er3\n\t"
		"sub.l er2,er2\n\t"
		"mov.l %2,er1\n\t"
		"mov.l %1,er0\n\t"
		"trapa #0\n\t"
		"cmp.l sp,er3\n\t"
		"beq 1f\n\t"
		"mov.l %4,er0\n\t"
		"mov.l %3,er1\n\t"
		"jsr @er1\n\t"
		"mov.l %5,er0\n\t"
		"trapa #0\n"
		"1:\n\t"
		"mov.l er0,%0"
		:"=r"(retval)
		:"i"(__NR_clone),"g"(clone_arg),"g"(fn),"g"(arg),"i"(__NR_exit)
		:"er0","er1","er2","er3");
	set_fs (fs);
	return retval;
}

void flush_thread(void)
{
}

/*
 * "h8300_fork()".. By the time we get here, the
 * non-volatile registers have also been saved on the
 * stack. We do some ugly pointer stuff here.. (see
 * also copy_thread)
 */

asmlinkage int h8300_fork(struct pt_regs *regs)
{
	return -EINVAL;
}

asmlinkage int h8300_vfork(struct pt_regs *regs)
{
	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL);
}

asmlinkage int h8300_clone(struct pt_regs *regs)
{
	unsigned long clone_flags;
	unsigned long newsp;

	/* syscall2 puts clone_flags in er1 and usp in er2 */
	clone_flags = regs->er1;
	newsp = regs->er2;
	if (!newsp)
		newsp  = rdusp();
	return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);

}

int copy_thread(int nr, unsigned long clone_flags,
                unsigned long usp, unsigned long topstk,
		 struct task_struct * p, struct pt_regs * regs)
{
	struct pt_regs * childregs;

A
Al Viro 已提交
201
	childregs = (struct pt_regs *) (THREAD_SIZE + task_stack_page(p)) - 1;
L
Linus Torvalds 已提交
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259

	*childregs = *regs;
	childregs->retpc = (unsigned long) ret_from_fork;
	childregs->er0 = 0;

	p->thread.usp = usp;
	p->thread.ksp = (unsigned long)childregs;

	return 0;
}

/*
 * sys_execve() executes a new program.
 */
asmlinkage int sys_execve(char *name, char **argv, char **envp,int dummy,...)
{
	int error;
	char * filename;
	struct pt_regs *regs = (struct pt_regs *) ((unsigned char *)&dummy-4);

	lock_kernel();
	filename = getname(name);
	error = PTR_ERR(filename);
	if (IS_ERR(filename))
		goto out;
	error = do_execve(filename, argv, envp, regs);
	putname(filename);
out:
	unlock_kernel();
	return error;
}

unsigned long thread_saved_pc(struct task_struct *tsk)
{
	return ((struct pt_regs *)tsk->thread.esp0)->pc;
}

unsigned long get_wchan(struct task_struct *p)
{
	unsigned long fp, pc;
	unsigned long stack_page;
	int count = 0;
	if (!p || p == current || p->state == TASK_RUNNING)
		return 0;

	stack_page = (unsigned long)p;
	fp = ((struct pt_regs *)p->thread.ksp)->er6;
	do {
		if (fp < stack_page+sizeof(struct thread_info) ||
		    fp >= 8184+stack_page)
			return 0;
		pc = ((unsigned long *)fp)[1];
		if (!in_sched_functions(pc))
			return pc;
		fp = *(unsigned long *) fp;
	} while (count++ < 16);
	return 0;
}