linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / arch / x86_64 / kernel / process.c
index 583d96f..818ab9e 100644 (file)
@@ -10,6 +10,7 @@
  *     Andi Kleen.
  *
  *     CPU hotplug support - ashok.raj@intel.com
+ *  $Id: process.c,v 1.38 2002/01/15 10:08:03 ak Exp $
  */
 
 /*
@@ -34,8 +35,8 @@
 #include <linux/ptrace.h>
 #include <linux/utsname.h>
 #include <linux/random.h>
-#include <linux/notifier.h>
 #include <linux/kprobes.h>
+#include <linux/notifier.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -63,20 +64,26 @@ EXPORT_SYMBOL(boot_option_idle_override);
  * Powermanagement idle function, if any..
  */
 void (*pm_idle)(void);
-EXPORT_SYMBOL(pm_idle);
 static DEFINE_PER_CPU(unsigned int, cpu_idle_state);
 
-static ATOMIC_NOTIFIER_HEAD(idle_notifier);
+static struct notifier_block *idle_notifier;
+static DEFINE_SPINLOCK(idle_notifier_lock);
 
 void idle_notifier_register(struct notifier_block *n)
 {
-       atomic_notifier_chain_register(&idle_notifier, n);
+       unsigned long flags;
+       spin_lock_irqsave(&idle_notifier_lock, flags);
+       notifier_chain_register(&idle_notifier, n);
+       spin_unlock_irqrestore(&idle_notifier_lock, flags);
 }
 EXPORT_SYMBOL_GPL(idle_notifier_register);
 
 void idle_notifier_unregister(struct notifier_block *n)
 {
-       atomic_notifier_chain_unregister(&idle_notifier, n);
+       unsigned long flags;
+       spin_lock_irqsave(&idle_notifier_lock, flags);
+       notifier_chain_unregister(&idle_notifier, n);
+       spin_unlock_irqrestore(&idle_notifier_lock, flags);
 }
 EXPORT_SYMBOL(idle_notifier_unregister);
 
@@ -86,13 +93,13 @@ static DEFINE_PER_CPU(enum idle_state, idle_state) = CPU_NOT_IDLE;
 void enter_idle(void)
 {
        __get_cpu_var(idle_state) = CPU_IDLE;
-       atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL);
+       notifier_call_chain(&idle_notifier, IDLE_START, NULL);
 }
 
 static void __exit_idle(void)
 {
        __get_cpu_var(idle_state) = CPU_NOT_IDLE;
-       atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL);
+       notifier_call_chain(&idle_notifier, IDLE_END, NULL);
 }
 
 /* Called from interrupts to signify idle end */
@@ -107,11 +114,11 @@ void exit_idle(void)
  * We use this if we don't have any better
  * idle routine..
  */
-static void default_idle(void)
+void default_idle(void)
 {
        local_irq_enable();
 
-       current_thread_info()->status &= ~TS_POLLING;
+       clear_thread_flag(TIF_POLLING_NRFLAG);
        smp_mb__after_clear_bit();
        while (!need_resched()) {
                local_irq_disable();
@@ -120,7 +127,7 @@ static void default_idle(void)
                else
                        local_irq_enable();
        }
-       current_thread_info()->status |= TS_POLLING;
+       set_thread_flag(TIF_POLLING_NRFLAG);
 }
 
 /*
@@ -203,7 +210,8 @@ static inline void play_dead(void)
  */
 void cpu_idle (void)
 {
-       current_thread_info()->status |= TS_POLLING;
+       set_thread_flag(TIF_POLLING_NRFLAG);
+
        /* endless idle loop with no priority at all */
        while (1) {
                while (!need_resched()) {
@@ -296,7 +304,7 @@ void __show_regs(struct pt_regs * regs)
                system_utsname.version);
        printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip);
        printk_address(regs->rip); 
-       printk("RSP: %04lx:%016lx  EFLAGS: %08lx\n", regs->ss, regs->rsp,
+       printk("\nRSP: %04lx:%016lx  EFLAGS: %08lx\n", regs->ss, regs->rsp,
                regs->eflags);
        printk("RAX: %016lx RBX: %016lx RCX: %016lx\n",
               regs->rax, regs->rbx, regs->rcx);
@@ -334,7 +342,7 @@ void show_regs(struct pt_regs *regs)
 {
        printk("CPU %d:", smp_processor_id());
        __show_regs(regs);
-       show_trace(NULL, regs, (void *)(regs + 1));
+       show_trace(&regs->rsp);
 }
 
 /*
@@ -345,6 +353,13 @@ void exit_thread(void)
        struct task_struct *me = current;
        struct thread_struct *t = &me->thread;
 
+       /*
+        * Remove function-return probe instances associated with this task
+        * and put them back on the free list. Do not insert an exit probe for
+        * this function, it will be disabled by kprobe_flush_task if you do.
+        */
+       kprobe_flush_task(me);
+
        if (me->thread.io_bitmap_ptr) { 
                struct tss_struct *tss = &per_cpu(init_tss, get_cpu());
 
@@ -364,11 +379,8 @@ void flush_thread(void)
        struct task_struct *tsk = current;
        struct thread_info *t = current_thread_info();
 
-       if (t->flags & _TIF_ABI_PENDING) {
+       if (t->flags & _TIF_ABI_PENDING)
                t->flags ^= (_TIF_ABI_PENDING | _TIF_IA32);
-               if (t->flags & _TIF_IA32)
-                       current_thread_info()->status |= TS_COMPAT;
-       }
 
        tsk->thread.debugreg0 = 0;
        tsk->thread.debugreg1 = 0;
@@ -496,7 +508,7 @@ out:
 /*
  * This special macro can be used to load a debugging register
  */
-#define loaddebug(thread,r) set_debugreg(thread->debugreg ## r, r)
+#define loaddebug(thread,r) set_debug(thread->debugreg ## r, r)
 
 /*
  *     switch_to(x,y) should switch tasks from x to y.
@@ -571,16 +583,18 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
                prev->gsindex = gsindex;
        }
 
-       /* Must be after DS reload */
-       unlazy_fpu(prev_p);
-
        /* 
-        * Switch the PDA and FPU contexts.
+        * Switch the PDA context.
         */
        prev->userrsp = read_pda(oldrsp); 
        write_pda(oldrsp, next->userrsp); 
        write_pda(pcurrent, next_p); 
 
+       /* This must be here to ensure both math_state_restore() and
+          kernel_fpu_begin() work consistently.
+          And the AMD workaround requires it to be after DS reload. */
+       unlazy_fpu(prev_p);
+
        write_pda(kernelstack,
                  task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET);
 
@@ -650,6 +664,12 @@ void set_personality_64bit(void)
 
        /* Make sure to be in 64bit mode */
        clear_thread_flag(TIF_IA32); 
+
+       /* TBD: overwrites user setup. Should have two bits.
+          But 64bit processes have always behaved this way,
+          so it's not too bad. The main problem is just that
+          32bit childs are affected again. */
+       current->personality &= ~READ_IMPLIES_EXEC;
 }
 
 asmlinkage long sys_fork(struct pt_regs *regs)
@@ -778,16 +798,10 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
        }
        case ARCH_GET_GS: { 
                unsigned long base;
-               unsigned gsindex;
                if (task->thread.gsindex == GS_TLS_SEL)
                        base = read_32bit_tls(task, GS_TLS);
-               else if (doit) {
-                       asm("movl %%gs,%0" : "=r" (gsindex));
-                       if (gsindex)
-                               rdmsrl(MSR_KERNEL_GS_BASE, base);
-                       else
-                               base = task->thread.gs;
-               }
+               else if (doit)
+                       rdmsrl(MSR_KERNEL_GS_BASE, base);
                else
                        base = task->thread.gs;
                ret = put_user(base, (unsigned long __user *)addr);