process.c 17.7 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 *  linux/arch/i386/kernel/process.c
 *
 *  Copyright (C) 1995  Linus Torvalds
 *
 *  Pentium III FXSR, SSE support
 *	Gareth Hughes <gareth@valinux.com>, May 2000
 */

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

#define __KERNEL_SYSCALLS__
#include <stdarg.h>

#include <linux/errno.h>
#include <linux/sched.h>
19
#include <linux/fs.h>
Linus Torvalds's avatar
Linus Torvalds committed
20 21
#include <linux/kernel.h>
#include <linux/mm.h>
22
#include <linux/elfcore.h>
Linus Torvalds's avatar
Linus Torvalds committed
23 24 25 26
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
Linus Torvalds's avatar
Linus Torvalds committed
27
#include <linux/slab.h>
Linus Torvalds's avatar
Linus Torvalds committed
28 29 30 31 32 33 34 35 36
#include <linux/vmalloc.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/interrupt.h>
#include <linux/config.h>
#include <linux/delay.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/mc146818rtc.h>
Ingo Molnar's avatar
Ingo Molnar committed
37
#include <linux/module.h>
38
#include <linux/kallsyms.h>
39
#include <linux/ptrace.h>
Linus Torvalds's avatar
Linus Torvalds committed
40 41 42 43 44 45 46 47

#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/ldt.h>
#include <asm/processor.h>
#include <asm/i387.h>
48
#include <asm/irq.h>
Linus Torvalds's avatar
Linus Torvalds committed
49 50 51 52 53 54
#include <asm/desc.h>
#ifdef CONFIG_MATH_EMULATION
#include <asm/math_emu.h>
#endif

#include <linux/irq.h>
55
#include <linux/err.h>
Linus Torvalds's avatar
Linus Torvalds committed
56 57 58 59 60

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

int hlt_counter;

Jens Axboe's avatar
Jens Axboe committed
61 62 63 64 65 66 67 68
/*
 * Return saved PC of a blocked thread.
 */
unsigned long thread_saved_pc(struct task_struct *tsk)
{
	return ((unsigned long *)tsk->thread.esp)[3];
}

Linus Torvalds's avatar
Linus Torvalds committed
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
/*
 * Powermanagement idle function, if any..
 */
void (*pm_idle)(void);

void disable_hlt(void)
{
	hlt_counter++;
}

void enable_hlt(void)
{
	hlt_counter--;
}

/*
 * We use this if we don't have any better
 * idle routine..
 */
88
void default_idle(void)
Linus Torvalds's avatar
Linus Torvalds committed
89
{
90
	if (!hlt_counter && current_cpu_data.hlt_works_ok) {
91
		local_irq_disable();
Linus Torvalds's avatar
Linus Torvalds committed
92
		if (!need_resched())
Linus Torvalds's avatar
Linus Torvalds committed
93 94
			safe_halt();
		else
95
			local_irq_enable();
Linus Torvalds's avatar
Linus Torvalds committed
96 97 98 99 100
	}
}

/*
 * On SMP it's slightly faster (but much more power-consuming!)
Linus Torvalds's avatar
Linus Torvalds committed
101
 * to poll the ->work.need_resched flag instead of waiting for the
Linus Torvalds's avatar
Linus Torvalds committed
102 103 104 105 106 107
 * cross-CPU IPI to arrive. Use this option with caution.
 */
static void poll_idle (void)
{
	int oldval;

108
	local_irq_enable();
Linus Torvalds's avatar
Linus Torvalds committed
109 110 111 112 113

	/*
	 * Deal with another CPU just having chosen a thread to
	 * run here:
	 */
114
	oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
Linus Torvalds's avatar
Linus Torvalds committed
115

116 117
	if (!oldval) {
		set_thread_flag(TIF_POLLING_NRFLAG);
Linus Torvalds's avatar
Linus Torvalds committed
118 119
		asm volatile(
			"2:"
120
			"testl %0, %1;"
Linus Torvalds's avatar
Linus Torvalds committed
121 122
			"rep; nop;"
			"je 2b;"
123 124 125 126 127 128
			: : "i"(_TIF_NEED_RESCHED), "m" (current_thread_info()->flags));

		clear_thread_flag(TIF_POLLING_NRFLAG);
	} else {
		set_need_resched();
	}
Linus Torvalds's avatar
Linus Torvalds committed
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
}

/*
 * 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)
{
	/* endless idle loop with no priority at all */
	while (1) {
		void (*idle)(void) = pm_idle;
		if (!idle)
			idle = default_idle;
144
		irq_stat[smp_processor_id()].idle_timestamp = jiffies;
Linus Torvalds's avatar
Linus Torvalds committed
145
		while (!need_resched())
Linus Torvalds's avatar
Linus Torvalds committed
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
			idle();
		schedule();
	}
}

static int __init idle_setup (char *str)
{
	if (!strncmp(str, "poll", 4)) {
		printk("using polling idle threads.\n");
		pm_idle = poll_idle;
	}

	return 1;
}

__setup("idle=", idle_setup);

void show_regs(struct pt_regs * regs)
{
	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;

	printk("\n");
Linus Torvalds's avatar
Linus Torvalds committed
168
	printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
169
	printk("EIP: %04x:[<%08lx>] CPU: %d\n",0xffff & regs->xcs,regs->eip, smp_processor_id());
Ingo Molnar's avatar
Ingo Molnar committed
170 171
	print_symbol("EIP is at %s\n", regs->eip);

Linus Torvalds's avatar
Linus Torvalds committed
172 173
	if (regs->xcs & 3)
		printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);
Linus Torvalds's avatar
Linus Torvalds committed
174
	printk(" EFLAGS: %08lx    %s\n",regs->eflags, print_tainted());
Linus Torvalds's avatar
Linus Torvalds committed
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
	printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
		regs->eax,regs->ebx,regs->ecx,regs->edx);
	printk("ESI: %08lx EDI: %08lx EBP: %08lx",
		regs->esi, regs->edi, regs->ebp);
	printk(" DS: %04x ES: %04x\n",
		0xffff & regs->xds,0xffff & regs->xes);

	__asm__("movl %%cr0, %0": "=r" (cr0));
	__asm__("movl %%cr2, %0": "=r" (cr2));
	__asm__("movl %%cr3, %0": "=r" (cr3));
	/* This could fault if %cr4 does not exist */
	__asm__("1: movl %%cr4, %0		\n"
		"2:				\n"
		".section __ex_table,\"a\"	\n"
		".long 1b,2b			\n"
		".previous			\n"
		: "=r" (cr4): "0" (0));
	printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4);
	show_trace(&regs->esp);
}

196 197 198 199 200 201 202 203 204 205 206 207 208 209
/*
 * This gets run with %ebx containing the
 * function to call, and %edx containing
 * the "args".
 */
extern void kernel_thread_helper(void);
__asm__(".align 4\n"
	"kernel_thread_helper:\n\t"
	"movl %edx,%eax\n\t"
	"pushl %edx\n\t"
	"call *%ebx\n\t"
	"pushl %eax\n\t"
	"call do_exit");

Linus Torvalds's avatar
Linus Torvalds committed
210 211 212 213 214
/*
 * Create a kernel thread
 */
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
215 216 217 218 219 220 221 222
	struct task_struct *p;
	struct pt_regs regs;

	memset(&regs, 0, sizeof(regs));

	regs.ebx = (unsigned long) fn;
	regs.edx = (unsigned long) arg;

223 224
	regs.xds = __USER_DS;
	regs.xes = __USER_DS;
225 226 227 228 229 230
	regs.orig_eax = -1;
	regs.eip = (unsigned long) kernel_thread_helper;
	regs.xcs = __KERNEL_CS;
	regs.eflags = 0x286;

	/* Ok, create the new process.. */
231
	p = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
232
	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
Linus Torvalds's avatar
Linus Torvalds committed
233 234 235 236 237 238 239
}

/*
 * Free current thread data structures etc..
 */
void exit_thread(void)
{
240 241 242 243 244 245 246
	struct task_struct *tsk = current;

	/* The process may have allocated an io port bitmap... nuke it. */
	if (unlikely(NULL != tsk->thread.ts_io_bitmap)) {
		kfree(tsk->thread.ts_io_bitmap);
		tsk->thread.ts_io_bitmap = NULL;
	}
Linus Torvalds's avatar
Linus Torvalds committed
247 248 249 250 251 252 253
}

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

	memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8);
Luca Barbieri's avatar
Luca Barbieri committed
254
	memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));	
Linus Torvalds's avatar
Linus Torvalds committed
255 256 257 258 259 260 261 262 263 264 265
	/*
	 * Forget coprocessor state..
	 */
	clear_fpu(tsk);
	tsk->used_math = 0;
}

void release_thread(struct task_struct *dead_task)
{
	if (dead_task->mm) {
		// temporary debugging check
Dave Jones's avatar
Dave Jones committed
266 267 268 269 270
		if (dead_task->mm->context.size) {
			printk("WARNING: dead process %8s still has LDT? <%p/%d>\n",
					dead_task->comm,
					dead_task->mm->context.ldt,
					dead_task->mm->context.size);
Linus Torvalds's avatar
Linus Torvalds committed
271 272 273
			BUG();
		}
	}
274 275

	release_x86_irqs(dead_task);
Linus Torvalds's avatar
Linus Torvalds committed
276 277
}

278 279 280 281 282 283 284 285 286
/*
 * This gets called before we allocate a new thread and copy
 * the current task into it.
 */
void prepare_to_copy(struct task_struct *tsk)
{
	unlazy_fpu(tsk);
}

Linus Torvalds's avatar
Linus Torvalds committed
287 288 289 290 291
int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
	unsigned long unused,
	struct task_struct * p, struct pt_regs * regs)
{
	struct pt_regs * childregs;
292
	struct task_struct *tsk;
293
	int err;
Linus Torvalds's avatar
Linus Torvalds committed
294

295
	childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p->thread_info)) - 1;
Linus Torvalds's avatar
Linus Torvalds committed
296 297 298
	struct_cpy(childregs, regs);
	childregs->eax = 0;
	childregs->esp = esp;
299
	p->set_child_tid = p->clear_child_tid = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
300 301 302 303 304 305 306 307 308

	p->thread.esp = (unsigned long) childregs;
	p->thread.esp0 = (unsigned long) (childregs+1);

	p->thread.eip = (unsigned long) ret_from_fork;

	savesegment(fs,p->thread.fs);
	savesegment(gs,p->thread.gs);

309
	tsk = current;
310 311 312 313 314 315 316 317
	if (unlikely(NULL != tsk->thread.ts_io_bitmap)) {
		p->thread.ts_io_bitmap = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
		if (!p->thread.ts_io_bitmap)
			return -ENOMEM;
		memcpy(p->thread.ts_io_bitmap, tsk->thread.ts_io_bitmap,
			IO_BITMAP_BYTES);
	}

318 319 320 321 322 323 324 325
	/*
	 * Set a new TLS for the child thread?
	 */
	if (clone_flags & CLONE_SETTLS) {
		struct desc_struct *desc;
		struct user_desc info;
		int idx;

326
		err = -EFAULT;
327
		if (copy_from_user(&info, (void __user *)childregs->esi, sizeof(info)))
328 329
			goto out;
		err = -EINVAL;
330
		if (LDT_empty(&info))
331
			goto out;
332 333 334

		idx = info.entry_number;
		if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
335
			goto out;
336 337 338 339 340

		desc = p->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;
		desc->a = LDT_entry_a(&info);
		desc->b = LDT_entry_b(&info);
	}
341 342 343 344 345 346

	err = 0;
 out:
	if (err && p->thread.ts_io_bitmap)
		kfree(p->thread.ts_io_bitmap);
	return err;
Linus Torvalds's avatar
Linus Torvalds committed
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 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
}

/*
 * fill in the user structure for a core dump..
 */
void dump_thread(struct pt_regs * regs, struct user * dump)
{
	int i;

/* changed the size calculations - should hopefully work better. lbt */
	dump->magic = CMAGIC;
	dump->start_code = 0;
	dump->start_stack = regs->esp & ~(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;
	for (i = 0; i < 8; i++)
		dump->u_debugreg[i] = current->thread.debugreg[i];  

	if (dump->start_stack < TASK_SIZE)
		dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;

	dump->regs.ebx = regs->ebx;
	dump->regs.ecx = regs->ecx;
	dump->regs.edx = regs->edx;
	dump->regs.esi = regs->esi;
	dump->regs.edi = regs->edi;
	dump->regs.ebp = regs->ebp;
	dump->regs.eax = regs->eax;
	dump->regs.ds = regs->xds;
	dump->regs.es = regs->xes;
	savesegment(fs,dump->regs.fs);
	savesegment(gs,dump->regs.gs);
	dump->regs.orig_eax = regs->orig_eax;
	dump->regs.eip = regs->eip;
	dump->regs.cs = regs->xcs;
	dump->regs.eflags = regs->eflags;
	dump->regs.esp = regs->esp;
	dump->regs.ss = regs->xss;

	dump->u_fpvalid = dump_fpu (regs, &dump->i387);
}

391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
/* 
 * Capture the user space registers if the task is not running (in user space)
 */
int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
{
	struct pt_regs ptregs;
	
	ptregs = *(struct pt_regs *)
		((unsigned long)tsk->thread_info+THREAD_SIZE - sizeof(ptregs));
	ptregs.xcs &= 0xffff;
	ptregs.xds &= 0xffff;
	ptregs.xes &= 0xffff;
	ptregs.xss &= 0xffff;

	elf_core_copy_regs(regs, &ptregs);

	return 1;
}

Linus Torvalds's avatar
Linus Torvalds committed
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
/*
 * This special macro can be used to load a debugging register
 */
#define loaddebug(thread,register) \
		__asm__("movl %0,%%db" #register  \
			: /* no output */ \
			:"r" (thread->debugreg[register]))

/*
 *	switch_to(x,yn) should switch tasks from x to y.
 *
 * We fsave/fwait so that an exception goes off at the right time
 * (as a call from the fsave or fwait in effect) rather than to
 * the wrong process. Lazy FP saving no longer makes any sense
 * with modern CPU's, and this simplifies a lot of things (SMP
 * and UP become the same).
 *
 * NOTE! We used to use the x86 hardware context switching. The
 * reason for not using it any more becomes apparent when you
 * try to recover gracefully from saved state that is no longer
 * valid (stale segment register values in particular). With the
 * hardware task-switch, there is no way to fix up bad state in
 * a reasonable manner.
 *
 * The fact that Intel documents the hardware task-switching to
 * be slow is a fairly red herring - this code is not noticeably
 * faster. However, there _is_ some room for improvement here,
 * so the performance issues may eventually be a valid point.
 * More important, however, is the fact that this allows us much
 * more flexibility.
440 441 442 443
 *
 * The return value (in %eax) will be the "prev" task after
 * the task-switch, and shows up in ret_from_fork in entry.S,
 * for example.
Linus Torvalds's avatar
Linus Torvalds committed
444
 */
445
struct task_struct * __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
Linus Torvalds's avatar
Linus Torvalds committed
446 447 448
{
	struct thread_struct *prev = &prev_p->thread,
				 *next = &next_p->thread;
449 450
	int cpu = smp_processor_id();
	struct tss_struct *tss = init_tss + cpu;
Linus Torvalds's avatar
Linus Torvalds committed
451

452 453
	/* never put a printk in __switch_to... printk() calls wake_up*() indirectly */

Linus Torvalds's avatar
Linus Torvalds committed
454 455 456 457 458
	unlazy_fpu(prev_p);

	/*
	 * Reload esp0, LDT and the page table pointer:
	 */
459
	load_esp0(tss, next->esp0);
Linus Torvalds's avatar
Linus Torvalds committed
460

461 462 463
	/*
	 * Load the per-thread Thread-Local Storage descriptor.
	 */
Ingo Molnar's avatar
Ingo Molnar committed
464
	load_TLS(next, cpu);
465

Linus Torvalds's avatar
Linus Torvalds committed
466 467 468 469 470 471 472 473
	/*
	 * Save away %fs and %gs. No need to save %es and %ds, as
	 * those are always kernel segments while inside the kernel.
	 */
	asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->fs));
	asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs));

	/*
Linus Torvalds's avatar
Linus Torvalds committed
474
	 * Restore %fs and %gs if needed.
Linus Torvalds's avatar
Linus Torvalds committed
475
	 */
Linus Torvalds's avatar
Linus Torvalds committed
476 477 478 479
	if (unlikely(prev->fs | prev->gs | next->fs | next->gs)) {
		loadsegment(fs, next->fs);
		loadsegment(gs, next->gs);
	}
Linus Torvalds's avatar
Linus Torvalds committed
480 481 482 483

	/*
	 * Now maybe reload the debug registers
	 */
Linus Torvalds's avatar
Linus Torvalds committed
484
	if (unlikely(next->debugreg[7])) {
Linus Torvalds's avatar
Linus Torvalds committed
485 486 487 488 489 490 491 492 493
		loaddebug(next, 0);
		loaddebug(next, 1);
		loaddebug(next, 2);
		loaddebug(next, 3);
		/* no 4 and 5 */
		loaddebug(next, 6);
		loaddebug(next, 7);
	}

494 495
	if (unlikely(prev->ts_io_bitmap || next->ts_io_bitmap)) {
		if (next->ts_io_bitmap) {
Linus Torvalds's avatar
Linus Torvalds committed
496 497 498 499 500 501 502 503
			/*
			 * 4 cachelines copy ... not good, but not that
			 * bad either. Anyone got something better?
			 * This only affects processes which use ioperm().
			 * [Putting the TSSs into 4k-tlb mapped regions
			 * and playing VM tricks to switch the IO bitmap
			 * is not really acceptable.]
			 */
504 505
			memcpy(tss->io_bitmap, next->ts_io_bitmap,
				IO_BITMAP_BYTES);
Linus Torvalds's avatar
Linus Torvalds committed
506 507 508 509 510 511 512 513 514 515
			tss->bitmap = IO_BITMAP_OFFSET;
		} else
			/*
			 * a bitmap offset pointing outside of the TSS limit
			 * causes a nicely controllable SIGSEGV if a process
			 * tries to use a port IO instruction. The first
			 * sys_ioperm() call sets up the bitmap properly.
			 */
			tss->bitmap = INVALID_IO_BITMAP_OFFSET;
	}
516
	return prev_p;
Linus Torvalds's avatar
Linus Torvalds committed
517 518 519 520
}

asmlinkage int sys_fork(struct pt_regs regs)
{
Rusty Russell's avatar
Rusty Russell committed
521 522
	struct task_struct *p;

523
	p = do_fork(SIGCHLD, regs.esp, &regs, 0, NULL, NULL);
Rusty Russell's avatar
Rusty Russell committed
524
	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
Linus Torvalds's avatar
Linus Torvalds committed
525 526 527 528
}

asmlinkage int sys_clone(struct pt_regs regs)
{
Rusty Russell's avatar
Rusty Russell committed
529
	struct task_struct *p;
Linus Torvalds's avatar
Linus Torvalds committed
530 531
	unsigned long clone_flags;
	unsigned long newsp;
532
	int *parent_tidptr, *child_tidptr;
Linus Torvalds's avatar
Linus Torvalds committed
533 534 535

	clone_flags = regs.ebx;
	newsp = regs.ecx;
536 537
	parent_tidptr = (int *)regs.edx;
	child_tidptr = (int *)regs.edi;
Linus Torvalds's avatar
Linus Torvalds committed
538 539
	if (!newsp)
		newsp = regs.esp;
540
	p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0, parent_tidptr, child_tidptr);
Rusty Russell's avatar
Rusty Russell committed
541
	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
Linus Torvalds's avatar
Linus Torvalds committed
542 543 544 545 546 547 548 549 550 551 552 553 554 555
}

/*
 * 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(struct pt_regs regs)
{
Rusty Russell's avatar
Rusty Russell committed
556 557
	struct task_struct *p;

558
	p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, &regs, 0, NULL, NULL);
Rusty Russell's avatar
Rusty Russell committed
559
	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
Linus Torvalds's avatar
Linus Torvalds committed
560 561 562 563 564 565 566 567 568 569
}

/*
 * sys_execve() executes a new program.
 */
asmlinkage int sys_execve(struct pt_regs regs)
{
	int error;
	char * filename;

570
	filename = getname((char __user *) regs.ebx);
Linus Torvalds's avatar
Linus Torvalds committed
571 572 573
	error = PTR_ERR(filename);
	if (IS_ERR(filename))
		goto out;
574 575 576 577
	error = do_execve(filename,
			(char __user * __user *) regs.ecx,
			(char __user * __user *) regs.edx,
			&regs);
578
	if (error == 0) {
Linus Torvalds's avatar
Linus Torvalds committed
579
		current->ptrace &= ~PT_DTRACE;
580
		/* Make sure we don't return using sysenter.. */
581
		set_thread_flag(TIF_IRET);
582
	}
Linus Torvalds's avatar
Linus Torvalds committed
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
	putname(filename);
out:
	return error;
}

/*
 * These bracket the sleeping functions..
 */
extern void scheduling_functions_start_here(void);
extern void scheduling_functions_end_here(void);
#define first_sched	((unsigned long) scheduling_functions_start_here)
#define last_sched	((unsigned long) scheduling_functions_end_here)

unsigned long get_wchan(struct task_struct *p)
{
	unsigned long ebp, esp, eip;
	unsigned long stack_page;
	int count = 0;
	if (!p || p == current || p->state == TASK_RUNNING)
		return 0;
603
	stack_page = (unsigned long)p->thread_info;
Linus Torvalds's avatar
Linus Torvalds committed
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
	esp = p->thread.esp;
	if (!stack_page || esp < stack_page || esp > 8188+stack_page)
		return 0;
	/* include/asm-i386/system.h:switch_to() pushes ebp last. */
	ebp = *(unsigned long *) esp;
	do {
		if (ebp < stack_page || ebp > 8184+stack_page)
			return 0;
		eip = *(unsigned long *) (ebp+4);
		if (eip < first_sched || eip >= last_sched)
			return eip;
		ebp = *(unsigned long *) ebp;
	} while (count++ < 16);
	return 0;
}
#undef last_sched
#undef first_sched
621 622

/*
Ingo Molnar's avatar
Ingo Molnar committed
623
 * sys_alloc_thread_area: get a yet unused TLS descriptor index.
624
 */
Ingo Molnar's avatar
Ingo Molnar committed
625
static int get_free_idx(void)
626 627
{
	struct thread_struct *t = &current->thread;
Ingo Molnar's avatar
Ingo Molnar committed
628
	int idx;
629

Ingo Molnar's avatar
Ingo Molnar committed
630 631 632 633 634 635 636 637 638
	for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++)
		if (desc_empty(t->tls_array + idx))
			return idx + GDT_ENTRY_TLS_MIN;
	return -ESRCH;
}

/*
 * Set a given TLS descriptor:
 */
639
asmlinkage int sys_set_thread_area(struct user_desc __user *u_info)
Ingo Molnar's avatar
Ingo Molnar committed
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
{
	struct thread_struct *t = &current->thread;
	struct user_desc info;
	struct desc_struct *desc;
	int cpu, idx;

	if (copy_from_user(&info, u_info, sizeof(info)))
		return -EFAULT;
	idx = info.entry_number;

	/*
	 * index -1 means the kernel should try to find and
	 * allocate an empty descriptor:
	 */
	if (idx == -1) {
		idx = get_free_idx();
		if (idx < 0)
			return idx;
		if (put_user(idx, &u_info->entry_number))
			return -EFAULT;
	}

	if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
663 664
		return -EINVAL;

Ingo Molnar's avatar
Ingo Molnar committed
665
	desc = t->tls_array + idx - GDT_ENTRY_TLS_MIN;
666 667 668 669 670 671

	/*
	 * We must not get preempted while modifying the TLS.
	 */
	cpu = get_cpu();

Ingo Molnar's avatar
Ingo Molnar committed
672 673 674 675 676 677 678 679
	if (LDT_empty(&info)) {
		desc->a = 0;
		desc->b = 0;
	} else {
		desc->a = LDT_entry_a(&info);
		desc->b = LDT_entry_b(&info);
	}
	load_TLS(t, cpu);
680 681 682

	put_cpu();

Ingo Molnar's avatar
Ingo Molnar committed
683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705
	return 0;
}

/*
 * Get the current Thread-Local Storage area:
 */

#define GET_BASE(desc) ( \
	(((desc)->a >> 16) & 0x0000ffff) | \
	(((desc)->b << 16) & 0x00ff0000) | \
	( (desc)->b        & 0xff000000)   )

#define GET_LIMIT(desc) ( \
	((desc)->a & 0x0ffff) | \
	 ((desc)->b & 0xf0000) )
	
#define GET_32BIT(desc)		(((desc)->b >> 23) & 1)
#define GET_CONTENTS(desc)	(((desc)->b >> 10) & 3)
#define GET_WRITABLE(desc)	(((desc)->b >>  9) & 1)
#define GET_LIMIT_PAGES(desc)	(((desc)->b >> 23) & 1)
#define GET_PRESENT(desc)	(((desc)->b >> 15) & 1)
#define GET_USEABLE(desc)	(((desc)->b >> 20) & 1)

706
asmlinkage int sys_get_thread_area(struct user_desc __user *u_info)
Ingo Molnar's avatar
Ingo Molnar committed
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731
{
	struct user_desc info;
	struct desc_struct *desc;
	int idx;

	if (get_user(idx, &u_info->entry_number))
		return -EFAULT;
	if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
		return -EINVAL;

	desc = current->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;

	info.entry_number = idx;
	info.base_addr = GET_BASE(desc);
	info.limit = GET_LIMIT(desc);
	info.seg_32bit = GET_32BIT(desc);
	info.contents = GET_CONTENTS(desc);
	info.read_exec_only = !GET_WRITABLE(desc);
	info.limit_in_pages = GET_LIMIT_PAGES(desc);
	info.seg_not_present = !GET_PRESENT(desc);
	info.useable = GET_USEABLE(desc);

	if (copy_to_user(u_info, &info, sizeof(info)))
		return -EFAULT;
	return 0;
732 733
}