“d38de3c6156b97e4900a345124d06b6ead2d6bee”上不存在“fs/git@gitcode.net:openeuler/kernel.git”
process_32.c 10.4 KB
Newer Older
P
Paul Mundt 已提交
1 2
/*
 * arch/sh/kernel/process.c
L
Linus Torvalds 已提交
3
 *
P
Paul Mundt 已提交
4
 * This file handles the architecture-dependent parts of process handling..
L
Linus Torvalds 已提交
5 6 7 8
 *
 *  Copyright (C) 1995  Linus Torvalds
 *
 *  SuperH version:  Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
R
Ryusuke Sakato 已提交
9
 *		     Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC
P
Paul Mundt 已提交
10
 *		     Copyright (C) 2002 - 2007  Paul Mundt
L
Linus Torvalds 已提交
11 12 13 14
 */
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/elfcore.h>
15
#include <linux/pm.h>
L
Linus Torvalds 已提交
16
#include <linux/kallsyms.h>
17
#include <linux/kexec.h>
P
Paul Mundt 已提交
18
#include <linux/kdebug.h>
19
#include <linux/tick.h>
20
#include <linux/reboot.h>
21
#include <linux/fs.h>
22
#include <linux/preempt.h>
L
Linus Torvalds 已提交
23 24
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
P
Paul Mundt 已提交
25
#include <asm/pgalloc.h>
26
#include <asm/system.h>
P
Paul Mundt 已提交
27
#include <asm/ubc.h>
28
#include <asm/fpu.h>
P
Paul Mundt 已提交
29
#include <asm/syscalls.h>
L
Linus Torvalds 已提交
30

P
Paul Mundt 已提交
31
static int hlt_counter;
L
Linus Torvalds 已提交
32 33
int ubc_usercnt = 0;

34 35 36 37
void (*pm_idle)(void);
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);

38 39 40 41 42 43 44 45 46 47 48 49 50 51
static int __init nohlt_setup(char *__unused)
{
	hlt_counter = 1;
	return 1;
}
__setup("nohlt", nohlt_setup);

static int __init hlt_setup(char *__unused)
{
	hlt_counter = 0;
	return 1;
}
__setup("hlt", hlt_setup);

A
Adrian Bunk 已提交
52
static void default_idle(void)
53
{
54 55 56 57 58 59 60 61 62 63 64
	if (!hlt_counter) {
		clear_thread_flag(TIF_POLLING_NRFLAG);
		smp_mb__after_clear_bit();
		set_bl_bit();
		while (!need_resched())
			cpu_sleep();
		clear_bl_bit();
		set_thread_flag(TIF_POLLING_NRFLAG);
	} else
		while (!need_resched())
			cpu_relax();
65 66
}

67
void cpu_idle(void)
L
Linus Torvalds 已提交
68
{
69 70
	set_thread_flag(TIF_POLLING_NRFLAG);

L
Linus Torvalds 已提交
71 72
	/* endless idle loop with no priority at all */
	while (1) {
73 74 75 76 77
		void (*idle)(void) = pm_idle;

		if (!idle)
			idle = default_idle;

78
		tick_nohz_stop_sched_tick(1);
79 80
		while (!need_resched())
			idle();
81
		tick_nohz_restart_sched_tick();
L
Linus Torvalds 已提交
82

83
		preempt_enable_no_resched();
L
Linus Torvalds 已提交
84
		schedule();
85
		preempt_disable();
P
Paul Mundt 已提交
86
		check_pgt_cache();
L
Linus Torvalds 已提交
87 88 89 90 91 92 93 94 95 96 97 98
	}
}

void machine_restart(char * __unused)
{
	/* SR.BL=1 and invoke address error to let CPU reset (manual reset) */
	asm volatile("ldc %0, sr\n\t"
		     "mov.l @%1, %0" : : "r" (0x10000000), "r" (0x80000001));
}

void machine_halt(void)
{
99
	local_irq_disable();
L
Linus Torvalds 已提交
100 101 102 103 104 105 106

	while (1)
		cpu_sleep();
}

void machine_power_off(void)
{
107 108
	if (pm_power_off)
		pm_power_off();
L
Linus Torvalds 已提交
109 110 111 112 113
}

void show_regs(struct pt_regs * regs)
{
	printk("\n");
114
	printk("Pid : %d, Comm: %20s\n", task_pid_nr(current), current->comm);
115 116 117 118 119
	printk("CPU : %d    %s  (%s %.*s)\n",
	       smp_processor_id(), print_tainted(), init_utsname()->release,
	       (int)strcspn(init_utsname()->version, " "),
	       init_utsname()->version);

120
	print_symbol("PC is at %s\n", instruction_pointer(regs));
121 122
	print_symbol("PR is at %s\n", regs->pr);

L
Linus Torvalds 已提交
123 124 125
	printk("PC  : %08lx SP  : %08lx SR  : %08lx ",
	       regs->pc, regs->regs[15], regs->sr);
#ifdef CONFIG_MMU
126
	printk("TEA : %08x\n", ctrl_inl(MMU_TEA));
L
Linus Torvalds 已提交
127
#else
128
	printk("\n");
L
Linus Torvalds 已提交
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
#endif

	printk("R0  : %08lx R1  : %08lx R2  : %08lx R3  : %08lx\n",
	       regs->regs[0],regs->regs[1],
	       regs->regs[2],regs->regs[3]);
	printk("R4  : %08lx R5  : %08lx R6  : %08lx R7  : %08lx\n",
	       regs->regs[4],regs->regs[5],
	       regs->regs[6],regs->regs[7]);
	printk("R8  : %08lx R9  : %08lx R10 : %08lx R11 : %08lx\n",
	       regs->regs[8],regs->regs[9],
	       regs->regs[10],regs->regs[11]);
	printk("R12 : %08lx R13 : %08lx R14 : %08lx\n",
	       regs->regs[12],regs->regs[13],
	       regs->regs[14]);
	printk("MACH: %08lx MACL: %08lx GBR : %08lx PR  : %08lx\n",
	       regs->mach, regs->macl, regs->gbr, regs->pr);

146
	show_trace(NULL, (unsigned long *)regs->regs[15], regs);
L
Linus Torvalds 已提交
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
}

/*
 * Create a kernel thread
 */

/*
 * This is the mechanism for creating a new kernel thread.
 *
 */
extern void kernel_thread_helper(void);
__asm__(".align 5\n"
	"kernel_thread_helper:\n\t"
	"jsr	@r5\n\t"
	" nop\n\t"
	"mov.l	1f, r1\n\t"
	"jsr	@r1\n\t"
	" mov	r0, r4\n\t"
	".align 2\n\t"
	"1:.long do_exit");

P
Paul Mundt 已提交
168
/* Don't use this in BL=1(cli).  Or else, CPU resets! */
L
Linus Torvalds 已提交
169
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
P
Paul Mundt 已提交
170
{
L
Linus Torvalds 已提交
171
	struct pt_regs regs;
172
	int pid;
L
Linus Torvalds 已提交
173 174

	memset(&regs, 0, sizeof(regs));
P
Paul Mundt 已提交
175 176
	regs.regs[4] = (unsigned long)arg;
	regs.regs[5] = (unsigned long)fn;
L
Linus Torvalds 已提交
177

P
Paul Mundt 已提交
178
	regs.pc = (unsigned long)kernel_thread_helper;
L
Linus Torvalds 已提交
179 180 181
	regs.sr = (1 << 30);

	/* Ok, create the new process.. */
182 183 184 185 186 187
	pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
		      &regs, 0, NULL, NULL);

	trace_mark(kernel_arch_kthread_create, "pid %d fn %p", pid, fn);

	return pid;
L
Linus Torvalds 已提交
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
}

/*
 * Free current thread data structures etc..
 */
void exit_thread(void)
{
	if (current->thread.ubc_pc) {
		current->thread.ubc_pc = 0;
		ubc_usercnt -= 1;
	}
}

void flush_thread(void)
{
#if defined(CONFIG_SH_FPU)
	struct task_struct *tsk = current;
	/* Forget lazy FPU state */
A
Al Viro 已提交
206
	clear_fpu(tsk, task_pt_regs(tsk));
L
Linus Torvalds 已提交
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
	clear_used_math();
#endif
}

void release_thread(struct task_struct *dead_task)
{
	/* do nothing */
}

/* Fill in the fpu structure for a core dump.. */
int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
{
	int fpvalid = 0;

#if defined(CONFIG_SH_FPU)
	struct task_struct *tsk = current;

	fpvalid = !!tsk_used_math(tsk);
	if (fpvalid) {
		unlazy_fpu(tsk, regs);
		memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
	}
#endif

	return fpvalid;
}

asmlinkage void ret_from_fork(void);

int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
		unsigned long unused,
		struct task_struct *p, struct pt_regs *regs)
{
240
	struct thread_info *ti = task_thread_info(p);
L
Linus Torvalds 已提交
241 242 243 244 245 246 247 248 249
	struct pt_regs *childregs;
#if defined(CONFIG_SH_FPU)
	struct task_struct *tsk = current;

	unlazy_fpu(tsk, regs);
	p->thread.fpu = tsk->thread.fpu;
	copy_to_stopped_child_used_math(p);
#endif

A
Al Viro 已提交
250
	childregs = task_pt_regs(p);
L
Linus Torvalds 已提交
251 252 253 254
	*childregs = *regs;

	if (user_mode(regs)) {
		childregs->regs[15] = usp;
255
		ti->addr_limit = USER_DS;
L
Linus Torvalds 已提交
256
	} else {
257
		childregs->regs[15] = (unsigned long)childregs;
258
		ti->addr_limit = KERNEL_DS;
L
Linus Torvalds 已提交
259
	}
P
Paul Mundt 已提交
260

261
	if (clone_flags & CLONE_SETTLS)
L
Linus Torvalds 已提交
262
		childregs->gbr = childregs->regs[0];
P
Paul Mundt 已提交
263

L
Linus Torvalds 已提交
264 265 266 267 268 269 270 271 272 273 274
	childregs->regs[0] = 0; /* Set return value for child */

	p->thread.sp = (unsigned long) childregs;
	p->thread.pc = (unsigned long) ret_from_fork;

	p->thread.ubc_pc = 0;

	return 0;
}

/* Tracing by user break controller.  */
P
Paul Mundt 已提交
275
static void ubc_set_tracing(int asid, unsigned long pc)
L
Linus Torvalds 已提交
276
{
R
Ryusuke Sakato 已提交
277 278 279 280 281 282 283 284 285 286 287 288 289 290
#if defined(CONFIG_CPU_SH4A)
	unsigned long val;

	val = (UBC_CBR_ID_INST | UBC_CBR_RW_READ | UBC_CBR_CE);
	val |= (UBC_CBR_AIE | UBC_CBR_AIV_SET(asid));

	ctrl_outl(val, UBC_CBR0);
	ctrl_outl(pc,  UBC_CAR0);
	ctrl_outl(0x0, UBC_CAMR0);
	ctrl_outl(0x0, UBC_CBCR);

	val = (UBC_CRR_RES | UBC_CRR_PCB | UBC_CRR_BIE);
	ctrl_outl(val, UBC_CRR0);

P
Paul Mundt 已提交
291
	/* Read UBC register that we wrote last, for checking update */
R
Ryusuke Sakato 已提交
292 293 294
	val = ctrl_inl(UBC_CRR0);

#else	/* CONFIG_CPU_SH4A */
L
Linus Torvalds 已提交
295 296
	ctrl_outl(pc, UBC_BARA);

297
#ifdef CONFIG_MMU
298
	ctrl_outb(asid, UBC_BASRA);
299
#endif
L
Linus Torvalds 已提交
300 301 302

	ctrl_outl(0, UBC_BAMRA);

303
	if (current_cpu_data.type == CPU_SH7729 ||
P
Paul Mundt 已提交
304 305
	    current_cpu_data.type == CPU_SH7710 ||
	    current_cpu_data.type == CPU_SH7712) {
L
Linus Torvalds 已提交
306 307 308 309 310 311
		ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA);
		ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR);
	} else {
		ctrl_outw(BBR_INST | BBR_READ, UBC_BBRA);
		ctrl_outw(BRCR_PCBA, UBC_BRCR);
	}
R
Ryusuke Sakato 已提交
312
#endif	/* CONFIG_CPU_SH4A */
L
Linus Torvalds 已提交
313 314 315 316 317 318
}

/*
 *	switch_to(x,y) should switch tasks from x to y.
 *
 */
P
Paul Mundt 已提交
319 320
struct task_struct *__switch_to(struct task_struct *prev,
				struct task_struct *next)
L
Linus Torvalds 已提交
321 322
{
#if defined(CONFIG_SH_FPU)
A
Al Viro 已提交
323
	unlazy_fpu(prev, task_pt_regs(prev));
L
Linus Torvalds 已提交
324 325
#endif

326
#ifdef CONFIG_MMU
L
Linus Torvalds 已提交
327 328
	/*
	 * Restore the kernel mode register
P
Paul Mundt 已提交
329
	 *	k7 (r7_bank1)
L
Linus Torvalds 已提交
330 331 332
	 */
	asm volatile("ldc	%0, r7_bank"
		     : /* no output */
A
Al Viro 已提交
333
		     : "r" (task_thread_info(next)));
334
#endif
L
Linus Torvalds 已提交
335 336 337 338 339

	/* If no tasks are using the UBC, we're done */
	if (ubc_usercnt == 0)
		/* If no tasks are using the UBC, we're done */;
	else if (next->thread.ubc_pc && next->mm) {
340 341
		int asid = 0;
#ifdef CONFIG_MMU
P
Paul Mundt 已提交
342
		asid |= cpu_asid(smp_processor_id(), next->mm);
343 344
#endif
		ubc_set_tracing(asid, next->thread.ubc_pc);
L
Linus Torvalds 已提交
345
	} else {
R
Ryusuke Sakato 已提交
346 347 348 349
#if defined(CONFIG_CPU_SH4A)
		ctrl_outl(UBC_CBR_INIT, UBC_CBR0);
		ctrl_outl(UBC_CRR_INIT, UBC_CRR0);
#else
L
Linus Torvalds 已提交
350 351
		ctrl_outw(0, UBC_BBRA);
		ctrl_outw(0, UBC_BBRB);
R
Ryusuke Sakato 已提交
352
#endif
L
Linus Torvalds 已提交
353 354 355 356 357 358 359
	}

	return prev;
}

asmlinkage int sys_fork(unsigned long r4, unsigned long r5,
			unsigned long r6, unsigned long r7,
S
Stuart Menefy 已提交
360
			struct pt_regs __regs)
L
Linus Torvalds 已提交
361 362
{
#ifdef CONFIG_MMU
363
	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
S
Stuart Menefy 已提交
364
	return do_fork(SIGCHLD, regs->regs[15], regs, 0, NULL, NULL);
L
Linus Torvalds 已提交
365 366 367 368 369 370 371 372 373
#else
	/* fork almost works, enough to trick you into looking elsewhere :-( */
	return -EINVAL;
#endif
}

asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
			 unsigned long parent_tidptr,
			 unsigned long child_tidptr,
S
Stuart Menefy 已提交
374
			 struct pt_regs __regs)
L
Linus Torvalds 已提交
375
{
S
Stuart Menefy 已提交
376
	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
L
Linus Torvalds 已提交
377
	if (!newsp)
S
Stuart Menefy 已提交
378 379
		newsp = regs->regs[15];
	return do_fork(clone_flags, newsp, regs, 0,
P
Paul Mundt 已提交
380 381
			(int __user *)parent_tidptr,
			(int __user *)child_tidptr);
L
Linus Torvalds 已提交
382 383 384 385 386 387 388 389 390 391 392 393 394 395
}

/*
 * This is trivial, and on the face of it looks like it
 * could equally well be done in user mode.
 *
 * Not so, for quite unobvious reasons - register pressure.
 * In user mode vfork() cannot have a stack frame, and if
 * done by calling the "clone()" system call directly, you
 * do not have enough call-clobbered registers to hold all
 * the information you need.
 */
asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
			 unsigned long r6, unsigned long r7,
S
Stuart Menefy 已提交
396
			 struct pt_regs __regs)
L
Linus Torvalds 已提交
397
{
S
Stuart Menefy 已提交
398 399
	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->regs[15], regs,
L
Linus Torvalds 已提交
400 401 402 403 404 405
		       0, NULL, NULL);
}

/*
 * sys_execve() executes a new program.
 */
406 407
asmlinkage int sys_execve(char __user *ufilename, char __user * __user *uargv,
			  char __user * __user *uenvp, unsigned long r7,
S
Stuart Menefy 已提交
408
			  struct pt_regs __regs)
L
Linus Torvalds 已提交
409
{
S
Stuart Menefy 已提交
410
	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
L
Linus Torvalds 已提交
411 412 413
	int error;
	char *filename;

414
	filename = getname(ufilename);
L
Linus Torvalds 已提交
415 416 417 418
	error = PTR_ERR(filename);
	if (IS_ERR(filename))
		goto out;

419
	error = do_execve(filename, uargv, uenvp, regs);
L
Linus Torvalds 已提交
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
	if (error == 0) {
		task_lock(current);
		current->ptrace &= ~PT_DTRACE;
		task_unlock(current);
	}
	putname(filename);
out:
	return error;
}

unsigned long get_wchan(struct task_struct *p)
{
	unsigned long pc;

	if (!p || p == current || p->state == TASK_RUNNING)
		return 0;

	/*
	 * The same comment as on the Alpha applies here, too ...
	 */
	pc = thread_saved_pc(p);
441 442

#ifdef CONFIG_FRAME_POINTER
L
Linus Torvalds 已提交
443
	if (in_sched_functions(pc)) {
444
		unsigned long schedule_frame = (unsigned long)p->thread.sp;
P
Paul Mundt 已提交
445
		return ((unsigned long *)schedule_frame)[21];
L
Linus Torvalds 已提交
446
	}
447
#endif
P
Paul Mundt 已提交
448

L
Linus Torvalds 已提交
449 450 451
	return pc;
}

S
Stuart Menefy 已提交
452
asmlinkage void break_point_trap(void)
L
Linus Torvalds 已提交
453 454
{
	/* Clear tracing.  */
R
Ryusuke Sakato 已提交
455 456 457 458
#if defined(CONFIG_CPU_SH4A)
	ctrl_outl(UBC_CBR_INIT, UBC_CBR0);
	ctrl_outl(UBC_CRR_INIT, UBC_CRR0);
#else
L
Linus Torvalds 已提交
459 460
	ctrl_outw(0, UBC_BBRA);
	ctrl_outw(0, UBC_BBRB);
R
Ryusuke Sakato 已提交
461
#endif
L
Linus Torvalds 已提交
462 463 464 465 466
	current->thread.ubc_pc = 0;
	ubc_usercnt -= 1;

	force_sig(SIGTRAP, current);
}