process.c 9.9 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
6
7
8
9
10
11
12
/*
 *  linux/arch/arm/kernel/process.c
 *
 *  Copyright (C) 1996-2000 Russell King - Converted to ARM.
 *  Original Copyright (C) 1995  Linus Torvalds
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <stdarg.h>

13
#include <linux/export.h>
Linus Torvalds's avatar
Linus Torvalds committed
14
15
16
17
18
19
20
21
22
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/user.h>
#include <linux/interrupt.h>
#include <linux/kallsyms.h>
#include <linux/init.h>
23
#include <linux/elfcore.h>
24
#include <linux/pm.h>
25
#include <linux/tick.h>
26
#include <linux/utsname.h>
27
#include <linux/uaccess.h>
28
#include <linux/random.h>
29
#include <linux/hw_breakpoint.h>
30
#include <linux/leds.h>
Linus Torvalds's avatar
Linus Torvalds committed
31
32

#include <asm/processor.h>
33
#include <asm/thread_notify.h>
34
#include <asm/stacktrace.h>
35
#include <asm/system_misc.h>
36
#include <asm/mach/time.h>
37
#include <asm/tls.h>
38
#include <asm/vdso.h>
Linus Torvalds's avatar
Linus Torvalds committed
39

40
41
42
43
44
45
#ifdef CONFIG_CC_STACKPROTECTOR
#include <linux/stackprotector.h>
unsigned long __stack_chk_guard __read_mostly;
EXPORT_SYMBOL(__stack_chk_guard);
#endif

46
static const char *processor_modes[] __maybe_unused = {
47
48
  "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
  "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26",
49
50
  "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "MON_32" , "ABT_32" ,
  "UK8_32" , "UK9_32" , "HYP_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32"
51
52
};

53
static const char *isa_modes[] __maybe_unused = {
54
55
56
  "ARM" , "Thumb" , "Jazelle", "ThumbEE"
};

Linus Torvalds's avatar
Linus Torvalds committed
57
/*
Nicolas Pitre's avatar
Nicolas Pitre committed
58
 * This is our default idle handler.
Linus Torvalds's avatar
Linus Torvalds committed
59
 */
Nicolas Pitre's avatar
Nicolas Pitre committed
60
61
62

void (*arm_pm_idle)(void);

63
64
65
66
67
/*
 * Called from the core idle loop.
 */

void arch_cpu_idle(void)
Linus Torvalds's avatar
Linus Torvalds committed
68
{
Nicolas Pitre's avatar
Nicolas Pitre committed
69
70
71
	if (arm_pm_idle)
		arm_pm_idle();
	else
Nicolas Pitre's avatar
Nicolas Pitre committed
72
		cpu_do_idle();
73
	local_irq_enable();
Linus Torvalds's avatar
Linus Torvalds committed
74
75
}

Thomas Gleixner's avatar
Thomas Gleixner committed
76
void arch_cpu_idle_prepare(void)
Linus Torvalds's avatar
Linus Torvalds committed
77
78
{
	local_fiq_enable();
Thomas Gleixner's avatar
Thomas Gleixner committed
79
}
Linus Torvalds's avatar
Linus Torvalds committed
80

Thomas Gleixner's avatar
Thomas Gleixner committed
81
82
83
84
85
void arch_cpu_idle_enter(void)
{
	ledtrig_cpu(CPU_LED_IDLE_START);
#ifdef CONFIG_PL310_ERRATA_769419
	wmb();
86
#endif
Thomas Gleixner's avatar
Thomas Gleixner committed
87
}
88

Thomas Gleixner's avatar
Thomas Gleixner committed
89
90
91
92
93
94
95
96
97
98
void arch_cpu_idle_exit(void)
{
	ledtrig_cpu(CPU_LED_IDLE_END);
}

#ifdef CONFIG_HOTPLUG_CPU
void arch_cpu_idle_dead(void)
{
	cpu_die();
}
99
#endif
Thomas Gleixner's avatar
Thomas Gleixner committed
100

Russell King's avatar
Russell King committed
101
void __show_regs(struct pt_regs *regs)
Linus Torvalds's avatar
Linus Torvalds committed
102
{
103
104
	unsigned long flags;
	char buf[64];
Linus Torvalds's avatar
Linus Torvalds committed
105

106
107
	show_regs_print_info(KERN_DEFAULT);

Linus Torvalds's avatar
Linus Torvalds committed
108
109
	print_symbol("PC is at %s\n", instruction_pointer(regs));
	print_symbol("LR is at %s\n", regs->ARM_lr);
110
	printk("pc : [<%08lx>]    lr : [<%08lx>]    psr: %08lx\n"
Linus Torvalds's avatar
Linus Torvalds committed
111
	       "sp : %08lx  ip : %08lx  fp : %08lx\n",
112
113
		regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr,
		regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
Linus Torvalds's avatar
Linus Torvalds committed
114
115
116
117
118
119
120
121
122
	printk("r10: %08lx  r9 : %08lx  r8 : %08lx\n",
		regs->ARM_r10, regs->ARM_r9,
		regs->ARM_r8);
	printk("r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n",
		regs->ARM_r7, regs->ARM_r6,
		regs->ARM_r5, regs->ARM_r4);
	printk("r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n",
		regs->ARM_r3, regs->ARM_r2,
		regs->ARM_r1, regs->ARM_r0);
123
124
125
126
127
128
129
130

	flags = regs->ARM_cpsr;
	buf[0] = flags & PSR_N_BIT ? 'N' : 'n';
	buf[1] = flags & PSR_Z_BIT ? 'Z' : 'z';
	buf[2] = flags & PSR_C_BIT ? 'C' : 'c';
	buf[3] = flags & PSR_V_BIT ? 'V' : 'v';
	buf[4] = '\0';

131
#ifndef CONFIG_CPU_V7M
132
	printk("Flags: %s  IRQs o%s  FIQs o%s  Mode %s  ISA %s  Segment %s\n",
133
		buf, interrupts_enabled(regs) ? "n" : "ff",
Linus Torvalds's avatar
Linus Torvalds committed
134
135
		fast_interrupts_enabled(regs) ? "n" : "ff",
		processor_modes[processor_mode(regs)],
136
		isa_modes[isa_mode(regs)],
Linus Torvalds's avatar
Linus Torvalds committed
137
		get_fs() == get_ds() ? "kernel" : "user");
138
139
140
141
#else
	printk("xPSR: %08lx\n", regs->ARM_cpsr);
#endif

142
#ifdef CONFIG_CPU_CP15
Linus Torvalds's avatar
Linus Torvalds committed
143
	{
144
		unsigned int ctrl;
145
146

		buf[0] = '\0';
147
#ifdef CONFIG_CPU_CP15_MMU
148
		{
149
			unsigned int transbase, dac = get_domain();
150
			asm("mrc p15, 0, %0, c2, c0\n\t"
151
			    : "=r" (transbase));
152
153
154
			snprintf(buf, sizeof(buf), "  Table: %08x  DAC: %08x",
			  	transbase, dac);
		}
155
#endif
156
157
158
159
		asm("mrc p15, 0, %0, c1, c0\n" : "=r" (ctrl));

		printk("Control: %08x%s\n", ctrl, buf);
	}
160
#endif
Linus Torvalds's avatar
Linus Torvalds committed
161
162
}

Russell King's avatar
Russell King committed
163
164
165
void show_regs(struct pt_regs * regs)
{
	__show_regs(regs);
166
	dump_stack();
Russell King's avatar
Russell King committed
167
168
}

169
170
171
172
ATOMIC_NOTIFIER_HEAD(thread_notify_head);

EXPORT_SYMBOL_GPL(thread_notify_head);

Linus Torvalds's avatar
Linus Torvalds committed
173
174
175
176
177
/*
 * Free current thread data structures etc..
 */
void exit_thread(void)
{
178
	thread_notify(THREAD_NOTIFY_EXIT, current_thread_info());
Linus Torvalds's avatar
Linus Torvalds committed
179
180
181
182
183
184
185
}

void flush_thread(void)
{
	struct thread_info *thread = current_thread_info();
	struct task_struct *tsk = current;

186
187
	flush_ptrace_hw_breakpoint(tsk);

Linus Torvalds's avatar
Linus Torvalds committed
188
189
	memset(thread->used_cp, 0, sizeof(thread->used_cp));
	memset(&tsk->thread.debug, 0, sizeof(struct debug_info));
190
191
	memset(&thread->fpstate, 0, sizeof(union fp_state));

192
193
	flush_tls();

194
	thread_notify(THREAD_NOTIFY_FLUSH, thread);
Linus Torvalds's avatar
Linus Torvalds committed
195
196
197
198
199
200
201
202
203
}

void release_thread(struct task_struct *dead_task)
{
}

asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");

int
Alexey Dobriyan's avatar
Alexey Dobriyan committed
204
copy_thread(unsigned long clone_flags, unsigned long stack_start,
205
	    unsigned long stk_sz, struct task_struct *p)
Linus Torvalds's avatar
Linus Torvalds committed
206
{
Al Viro's avatar
Al Viro committed
207
208
	struct thread_info *thread = task_thread_info(p);
	struct pt_regs *childregs = task_pt_regs(p);
Linus Torvalds's avatar
Linus Torvalds committed
209
210

	memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
211

212
213
214
215
216
217
218
219
	/*
	 * Copy the initial value of the domain access control register
	 * from the current thread: thread->addr_limit will have been
	 * copied from the current thread via setup_thread_stack() in
	 * kernel/fork.c
	 */
	thread->cpu_domain = get_domain();

220
221
	if (likely(!(p->flags & PF_KTHREAD))) {
		*childregs = *current_pt_regs();
222
		childregs->ARM_r0 = 0;
223
224
		if (stack_start)
			childregs->ARM_sp = stack_start;
225
	} else {
226
		memset(childregs, 0, sizeof(struct pt_regs));
227
228
229
230
		thread->cpu_context.r4 = stk_sz;
		thread->cpu_context.r5 = stack_start;
		childregs->ARM_cpsr = SVC_MODE;
	}
231
	thread->cpu_context.pc = (unsigned long)ret_from_fork;
Linus Torvalds's avatar
Linus Torvalds committed
232
233
	thread->cpu_context.sp = (unsigned long)childregs;

234
235
	clear_ptrace_hw_breakpoint(p);

Linus Torvalds's avatar
Linus Torvalds committed
236
	if (clone_flags & CLONE_SETTLS)
237
238
		thread->tp_value[0] = childregs->ARM_r3;
	thread->tp_value[1] = get_tpuser();
Linus Torvalds's avatar
Linus Torvalds committed
239

240
241
	thread_notify(THREAD_NOTIFY_COPY, thread);

Linus Torvalds's avatar
Linus Torvalds committed
242
243
244
	return 0;
}

245
246
247
248
249
250
251
252
253
/*
 * Fill in the task's elfregs structure for a core dump.
 */
int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs)
{
	elf_core_copy_regs(elfregs, task_pt_regs(t));
	return 1;
}

Linus Torvalds's avatar
Linus Torvalds committed
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
/*
 * fill in the fpe structure for a core dump...
 */
int dump_fpu (struct pt_regs *regs, struct user_fp *fp)
{
	struct thread_info *thread = current_thread_info();
	int used_math = thread->used_cp[1] | thread->used_cp[2];

	if (used_math)
		memcpy(fp, &thread->fpstate.soft, sizeof (*fp));

	return used_math != 0;
}
EXPORT_SYMBOL(dump_fpu);

unsigned long get_wchan(struct task_struct *p)
{
271
	struct stackframe frame;
272
	unsigned long stack_page;
Linus Torvalds's avatar
Linus Torvalds committed
273
274
275
276
	int count = 0;
	if (!p || p == current || p->state == TASK_RUNNING)
		return 0;

277
278
279
280
	frame.fp = thread_saved_fp(p);
	frame.sp = thread_saved_sp(p);
	frame.lr = 0;			/* recovered from the stack */
	frame.pc = thread_saved_pc(p);
281
	stack_page = (unsigned long)task_stack_page(p);
Linus Torvalds's avatar
Linus Torvalds committed
282
	do {
283
284
285
		if (frame.sp < stack_page ||
		    frame.sp >= stack_page + THREAD_SIZE ||
		    unwind_frame(&frame) < 0)
Linus Torvalds's avatar
Linus Torvalds committed
286
			return 0;
287
288
		if (!in_sched_functions(frame.pc))
			return frame.pc;
Linus Torvalds's avatar
Linus Torvalds committed
289
290
291
	} while (count ++ < 16);
	return 0;
}
292
293
294
295
296
297

unsigned long arch_randomize_brk(struct mm_struct *mm)
{
	unsigned long range_end = mm->brk + 0x02000000;
	return randomize_range(mm->brk, range_end, 0) ? : mm->brk;
}
298

299
#ifdef CONFIG_MMU
300
#ifdef CONFIG_KUSER_HELPERS
301
302
/*
 * The vectors page is always readable from user space for the
303
304
 * atomic helpers. Insert it into the gate_vma so that it is visible
 * through ptrace and /proc/<pid>/mem.
305
 */
306
307
308
309
310
static struct vm_area_struct gate_vma = {
	.vm_start	= 0xffff0000,
	.vm_end		= 0xffff0000 + PAGE_SIZE,
	.vm_flags	= VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC,
};
311

312
static int __init gate_vma_init(void)
313
{
314
	gate_vma.vm_page_prot = PAGE_READONLY_EXEC;
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
	return 0;
}
arch_initcall(gate_vma_init);

struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
{
	return &gate_vma;
}

int in_gate_area(struct mm_struct *mm, unsigned long addr)
{
	return (addr >= gate_vma.vm_start) && (addr < gate_vma.vm_end);
}

int in_gate_area_no_mm(unsigned long addr)
{
	return in_gate_area(NULL, addr);
332
}
333
#define is_gate_vma(vma)	((vma) == &gate_vma)
334
335
336
#else
#define is_gate_vma(vma)	0
#endif
337
338
339

const char *arch_vma_name(struct vm_area_struct *vma)
{
340
	return is_gate_vma(vma) ? "[vectors]" : NULL;
341
342
}

343
/* If possible, provide a placement hint at a random offset from the
344
 * stack for the sigpage and vdso pages.
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
 */
static unsigned long sigpage_addr(const struct mm_struct *mm,
				  unsigned int npages)
{
	unsigned long offset;
	unsigned long first;
	unsigned long last;
	unsigned long addr;
	unsigned int slots;

	first = PAGE_ALIGN(mm->start_stack);

	last = TASK_SIZE - (npages << PAGE_SHIFT);

	/* No room after stack? */
	if (first > last)
		return 0;

	/* Just enough room? */
	if (first == last)
		return first;

	slots = ((last - first) >> PAGE_SHIFT) + 1;

	offset = get_random_int() % slots;

	addr = first + (offset << PAGE_SHIFT);

	return addr;
374
375
}

376
static struct page *signal_page;
377
378
extern struct page *get_signal_page(void);

379
380
381
382
383
static const struct vm_special_mapping sigpage_mapping = {
	.name = "[sigpage]",
	.pages = &signal_page,
};

384
385
386
int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
{
	struct mm_struct *mm = current->mm;
387
	struct vm_area_struct *vma;
388
	unsigned long npages;
389
	unsigned long addr;
390
	unsigned long hint;
391
	int ret = 0;
392

393
394
395
	if (!signal_page)
		signal_page = get_signal_page();
	if (!signal_page)
396
397
		return -ENOMEM;

398
399
400
	npages = 1; /* for sigpage */
	npages += vdso_total_pages;

401
	down_write(&mm->mmap_sem);
402
403
	hint = sigpage_addr(mm, npages);
	addr = get_unmapped_area(NULL, hint, npages << PAGE_SHIFT, 0, 0);
404
405
406
407
408
	if (IS_ERR_VALUE(addr)) {
		ret = addr;
		goto up_fail;
	}

409
	vma = _install_special_mapping(mm, addr, PAGE_SIZE,
410
		VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
411
412
413
414
415
416
		&sigpage_mapping);

	if (IS_ERR(vma)) {
		ret = PTR_ERR(vma);
		goto up_fail;
	}
417

418
	mm->context.sigpage = addr;
419

420
421
422
423
424
425
	/* Unlike the sigpage, failure to install the vdso is unlikely
	 * to be fatal to the process, so no error check needed
	 * here.
	 */
	arm_install_vdso(mm, addr + PAGE_SIZE);

426
427
428
 up_fail:
	up_write(&mm->mmap_sem);
	return ret;
429
}
430
#endif