process.c 18.5 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
/*
 *  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..
 */

#include <stdarg.h>

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

#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>
47
#include <asm/irq.h>
Linus Torvalds's avatar
Linus Torvalds committed
48 49 50 51 52 53
#include <asm/desc.h>
#ifdef CONFIG_MATH_EMULATION
#include <asm/math_emu.h>
#endif

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

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

int hlt_counter;

Jens Axboe's avatar
Jens Axboe committed
60 61 62 63 64 65 66 67
/*
 * 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
68 69 70 71 72 73 74 75 76 77
/*
 * Powermanagement idle function, if any..
 */
void (*pm_idle)(void);

void disable_hlt(void)
{
	hlt_counter++;
}

78 79
EXPORT_SYMBOL(disable_hlt);

Linus Torvalds's avatar
Linus Torvalds committed
80 81 82 83 84
void enable_hlt(void)
{
	hlt_counter--;
}

85 86
EXPORT_SYMBOL(enable_hlt);

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

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

111
	local_irq_enable();
Linus Torvalds's avatar
Linus Torvalds committed
112 113 114 115 116

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

119 120
	if (!oldval) {
		set_thread_flag(TIF_POLLING_NRFLAG);
Linus Torvalds's avatar
Linus Torvalds committed
121 122
		asm volatile(
			"2:"
123
			"testl %0, %1;"
Linus Torvalds's avatar
Linus Torvalds committed
124 125
			"rep; nop;"
			"je 2b;"
126 127 128 129 130 131
			: : "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
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) {
144 145 146 147 148 149 150
		while (!need_resched()) {
			void (*idle)(void) = pm_idle;

			if (!idle)
				idle = default_idle;

			irq_stat[smp_processor_id()].idle_timestamp = jiffies;
Linus Torvalds's avatar
Linus Torvalds committed
151
			idle();
152
		}
Linus Torvalds's avatar
Linus Torvalds committed
153 154 155 156
		schedule();
	}
}

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
/*
 * This uses new MONITOR/MWAIT instructions on P4 processors with PNI,
 * which can obviate IPI to trigger checking of need_resched.
 * We execute MONITOR against need_resched and enter optimized wait state
 * through MWAIT. Whenever someone changes need_resched, we would be woken
 * up from MWAIT (without an IPI).
 */
static void mwait_idle(void)
{
	local_irq_enable();

	if (!need_resched()) {
		set_thread_flag(TIF_POLLING_NRFLAG);
		do {
			__monitor((void *)&current_thread_info()->flags, 0, 0);
			if (need_resched())
				break;
			__mwait(0, 0);
		} while (!need_resched());
		clear_thread_flag(TIF_POLLING_NRFLAG);
	}
}

void __init select_idle_routine(const struct cpuinfo_x86 *c)
{
	if (cpu_has(c, X86_FEATURE_MWAIT)) {
		printk("monitor/mwait feature present.\n");
		/*
		 * Skip, if setup has overridden idle.
186
		 * One CPU supports mwait => All CPUs supports mwait
187 188 189 190 191 192 193 194
		 */
		if (!pm_idle) {
			printk("using mwait in idle threads.\n");
			pm_idle = mwait_idle;
		}
	}
}

Linus Torvalds's avatar
Linus Torvalds committed
195 196 197 198 199
static int __init idle_setup (char *str)
{
	if (!strncmp(str, "poll", 4)) {
		printk("using polling idle threads.\n");
		pm_idle = poll_idle;
Andrew Morton's avatar
Andrew Morton committed
200
#ifdef CONFIG_X86_SMP
201 202 203
		if (smp_num_siblings > 1)
			printk("WARNING: polling idle and HT enabled, performance may degrade.\n");
#endif
204 205 206
	} else if (!strncmp(str, "halt", 4)) {
		printk("using halt in idle threads.\n");
		pm_idle = default_idle;
Linus Torvalds's avatar
Linus Torvalds committed
207 208 209 210 211 212 213 214 215 216 217 218
	}

	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
219
	printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
220
	printk("EIP: %04x:[<%08lx>] CPU: %d\n",0xffff & regs->xcs,regs->eip, smp_processor_id());
Ingo Molnar's avatar
Ingo Molnar committed
221 222
	print_symbol("EIP is at %s\n", regs->eip);

Linus Torvalds's avatar
Linus Torvalds committed
223 224
	if (regs->xcs & 3)
		printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);
225
	printk(" EFLAGS: %08lx    %s  (%s)\n",regs->eflags, print_tainted(),UTS_RELEASE);
Linus Torvalds's avatar
Linus Torvalds committed
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
	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);
244
	show_trace(NULL, &regs->esp);
Linus Torvalds's avatar
Linus Torvalds committed
245 246
}

247 248 249 250 251 252
/*
 * This gets run with %ebx containing the
 * function to call, and %edx containing
 * the "args".
 */
extern void kernel_thread_helper(void);
253 254
__asm__(".section .text\n"
	".align 4\n"
255 256 257 258 259
	"kernel_thread_helper:\n\t"
	"movl %edx,%eax\n\t"
	"pushl %edx\n\t"
	"call *%ebx\n\t"
	"pushl %eax\n\t"
260 261
	"call do_exit\n"
	".previous");
262

Linus Torvalds's avatar
Linus Torvalds committed
263 264 265 266 267
/*
 * Create a kernel thread
 */
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
268 269 270 271 272 273 274
	struct pt_regs regs;

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

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

275 276
	regs.xds = __USER_DS;
	regs.xes = __USER_DS;
277 278 279
	regs.orig_eax = -1;
	regs.eip = (unsigned long) kernel_thread_helper;
	regs.xcs = __KERNEL_CS;
280
	regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2;
281 282

	/* Ok, create the new process.. */
283
	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
284 285 286 287 288 289 290
}

/*
 * Free current thread data structures etc..
 */
void exit_thread(void)
{
291
	struct task_struct *tsk = current;
292
	struct thread_struct *t = &tsk->thread;
293 294

	/* The process may have allocated an io port bitmap... nuke it. */
295
	if (unlikely(NULL != t->io_bitmap_ptr)) {
296
		int cpu = get_cpu();
Shai Fultheim's avatar
Shai Fultheim committed
297
		struct tss_struct *tss = &per_cpu(init_tss, cpu);
298 299 300 301 302 303 304 305

		kfree(t->io_bitmap_ptr);
		t->io_bitmap_ptr = NULL;
		/*
		 * Careful, clear this in the TSS too:
		 */
		memset(tss->io_bitmap, 0xff, t->io_bitmap_max);
		t->io_bitmap_max = 0;
306
		put_cpu();
307
	}
Linus Torvalds's avatar
Linus Torvalds committed
308 309 310 311 312 313 314
}

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
315
	memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));	
Linus Torvalds's avatar
Linus Torvalds committed
316 317 318 319 320 321 322 323 324 325 326
	/*
	 * 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
327 328 329 330 331
		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
332 333 334
			BUG();
		}
	}
335 336

	release_x86_irqs(dead_task);
Linus Torvalds's avatar
Linus Torvalds committed
337 338
}

339 340 341 342 343 344 345 346 347
/*
 * 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
348 349 350 351 352
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;
353
	struct task_struct *tsk;
354
	int err;
Linus Torvalds's avatar
Linus Torvalds committed
355

356
	childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p->thread_info)) - 1;
Andrew Morton's avatar
Andrew Morton committed
357
	*childregs = *regs;
Linus Torvalds's avatar
Linus Torvalds committed
358 359
	childregs->eax = 0;
	childregs->esp = esp;
360
	p->set_child_tid = p->clear_child_tid = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
361 362 363 364 365 366 367 368 369

	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);

370
	tsk = current;
371 372
	if (unlikely(NULL != tsk->thread.io_bitmap_ptr)) {
		p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
373 374
		if (!p->thread.io_bitmap_ptr) {
			p->thread.io_bitmap_max = 0;
375
			return -ENOMEM;
376
		}
377
		memcpy(p->thread.io_bitmap_ptr, tsk->thread.io_bitmap_ptr,
378 379 380
			IO_BITMAP_BYTES);
	}

381 382 383 384 385 386 387 388
	/*
	 * Set a new TLS for the child thread?
	 */
	if (clone_flags & CLONE_SETTLS) {
		struct desc_struct *desc;
		struct user_desc info;
		int idx;

389
		err = -EFAULT;
390
		if (copy_from_user(&info, (void __user *)childregs->esi, sizeof(info)))
391 392
			goto out;
		err = -EINVAL;
393
		if (LDT_empty(&info))
394
			goto out;
395 396 397

		idx = info.entry_number;
		if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
398
			goto out;
399 400 401 402 403

		desc = p->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;
		desc->a = LDT_entry_a(&info);
		desc->b = LDT_entry_b(&info);
	}
404 405 406

	err = 0;
 out:
407
	if (err && p->thread.io_bitmap_ptr) {
408
		kfree(p->thread.io_bitmap_ptr);
409 410
		p->thread.io_bitmap_max = 0;
	}
411
	return err;
Linus Torvalds's avatar
Linus Torvalds committed
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 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
}

/*
 * 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);
}

456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
/* 
 * 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
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
/*
 * 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.
505 506 507 508
 *
 * 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
509
 */
510
struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
Linus Torvalds's avatar
Linus Torvalds committed
511 512 513
{
	struct thread_struct *prev = &prev_p->thread,
				 *next = &next_p->thread;
514
	int cpu = smp_processor_id();
Shai Fultheim's avatar
Shai Fultheim committed
515
	struct tss_struct *tss = &per_cpu(init_tss, cpu);
Linus Torvalds's avatar
Linus Torvalds committed
516

517 518
	/* never put a printk in __switch_to... printk() calls wake_up*() indirectly */

519
	__unlazy_fpu(prev_p);
Linus Torvalds's avatar
Linus Torvalds committed
520 521 522 523

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

526 527 528
	/*
	 * Load the per-thread Thread-Local Storage descriptor.
	 */
Ingo Molnar's avatar
Ingo Molnar committed
529
	load_TLS(next, cpu);
530

Linus Torvalds's avatar
Linus Torvalds committed
531 532 533 534 535 536 537 538
	/*
	 * 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
539
	 * Restore %fs and %gs if needed.
Linus Torvalds's avatar
Linus Torvalds committed
540
	 */
Linus Torvalds's avatar
Linus Torvalds committed
541 542 543 544
	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
545 546 547 548

	/*
	 * Now maybe reload the debug registers
	 */
Linus Torvalds's avatar
Linus Torvalds committed
549
	if (unlikely(next->debugreg[7])) {
Linus Torvalds's avatar
Linus Torvalds committed
550 551 552 553 554 555 556 557 558
		loaddebug(next, 0);
		loaddebug(next, 1);
		loaddebug(next, 2);
		loaddebug(next, 3);
		/* no 4 and 5 */
		loaddebug(next, 6);
		loaddebug(next, 7);
	}

559
	if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) {
560
		if (next->io_bitmap_ptr)
Linus Torvalds's avatar
Linus Torvalds committed
561
			/*
562 563
			 * Copy the relevant range of the IO bitmap.
			 * Normally this is 128 bytes or less:
Linus Torvalds's avatar
Linus Torvalds committed
564
			 */
565
			memcpy(tss->io_bitmap, next->io_bitmap_ptr,
566 567
				max(prev->io_bitmap_max, next->io_bitmap_max));
		else
Linus Torvalds's avatar
Linus Torvalds committed
568
			/*
569
			 * Clear any possible leftover bits:
Linus Torvalds's avatar
Linus Torvalds committed
570
			 */
571
			memset(tss->io_bitmap, 0xff, prev->io_bitmap_max);
Linus Torvalds's avatar
Linus Torvalds committed
572
	}
573
	return prev_p;
Linus Torvalds's avatar
Linus Torvalds committed
574 575 576 577
}

asmlinkage int sys_fork(struct pt_regs regs)
{
578
	return do_fork(SIGCHLD, regs.esp, &regs, 0, NULL, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
579 580 581 582 583 584
}

asmlinkage int sys_clone(struct pt_regs regs)
{
	unsigned long clone_flags;
	unsigned long newsp;
585
	int __user *parent_tidptr, *child_tidptr;
Linus Torvalds's avatar
Linus Torvalds committed
586 587 588

	clone_flags = regs.ebx;
	newsp = regs.ecx;
589 590
	parent_tidptr = (int __user *)regs.edx;
	child_tidptr = (int __user *)regs.edi;
Linus Torvalds's avatar
Linus Torvalds committed
591 592
	if (!newsp)
		newsp = regs.esp;
593
	return do_fork(clone_flags, newsp, &regs, 0, parent_tidptr, child_tidptr);
Linus Torvalds's avatar
Linus Torvalds committed
594 595 596 597 598 599 600 601 602 603 604 605 606 607
}

/*
 * 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)
{
608
	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, &regs, 0, NULL, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
609 610 611 612 613 614 615 616 617 618
}

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

619
	filename = getname((char __user *) regs.ebx);
Linus Torvalds's avatar
Linus Torvalds committed
620 621 622
	error = PTR_ERR(filename);
	if (IS_ERR(filename))
		goto out;
623 624 625 626
	error = do_execve(filename,
			(char __user * __user *) regs.ecx,
			(char __user * __user *) regs.edx,
			&regs);
627
	if (error == 0) {
Linus Torvalds's avatar
Linus Torvalds committed
628
		current->ptrace &= ~PT_DTRACE;
629
		/* Make sure we don't return using sysenter.. */
630
		set_thread_flag(TIF_IRET);
631
	}
Linus Torvalds's avatar
Linus Torvalds committed
632 633 634 635 636
	putname(filename);
out:
	return error;
}

637 638
#define top_esp                (THREAD_SIZE - sizeof(unsigned long))
#define top_ebp                (THREAD_SIZE - 2*sizeof(unsigned long))
Linus Torvalds's avatar
Linus Torvalds committed
639 640 641 642 643 644 645 646

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;
647
	stack_page = (unsigned long)p->thread_info;
Linus Torvalds's avatar
Linus Torvalds committed
648
	esp = p->thread.esp;
649
	if (!stack_page || esp < stack_page || esp > top_esp+stack_page)
Linus Torvalds's avatar
Linus Torvalds committed
650 651 652 653
		return 0;
	/* include/asm-i386/system.h:switch_to() pushes ebp last. */
	ebp = *(unsigned long *) esp;
	do {
654
		if (ebp < stack_page || ebp > top_ebp+stack_page)
Linus Torvalds's avatar
Linus Torvalds committed
655 656
			return 0;
		eip = *(unsigned long *) (ebp+4);
657
		if (!in_sched_functions(eip))
Linus Torvalds's avatar
Linus Torvalds committed
658 659 660 661 662
			return eip;
		ebp = *(unsigned long *) ebp;
	} while (count++ < 16);
	return 0;
}
663 664

/*
Ingo Molnar's avatar
Ingo Molnar committed
665
 * sys_alloc_thread_area: get a yet unused TLS descriptor index.
666
 */
Ingo Molnar's avatar
Ingo Molnar committed
667
static int get_free_idx(void)
668 669
{
	struct thread_struct *t = &current->thread;
Ingo Molnar's avatar
Ingo Molnar committed
670
	int idx;
671

Ingo Molnar's avatar
Ingo Molnar committed
672 673 674 675 676 677 678 679 680
	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:
 */
681
asmlinkage int sys_set_thread_area(struct user_desc __user *u_info)
Ingo Molnar's avatar
Ingo Molnar committed
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
{
	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)
705 706
		return -EINVAL;

Ingo Molnar's avatar
Ingo Molnar committed
707
	desc = t->tls_array + idx - GDT_ENTRY_TLS_MIN;
708 709 710 711 712 713

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

Ingo Molnar's avatar
Ingo Molnar committed
714 715 716 717 718 719 720 721
	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);
722 723 724

	put_cpu();

Ingo Molnar's avatar
Ingo Molnar committed
725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
	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) )
	
741
#define GET_32BIT(desc)		(((desc)->b >> 22) & 1)
Ingo Molnar's avatar
Ingo Molnar committed
742 743 744 745 746 747
#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)

748
asmlinkage int sys_get_thread_area(struct user_desc __user *u_info)
Ingo Molnar's avatar
Ingo Molnar committed
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773
{
	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;
774 775
}