Merge branch 'x86-x32-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-flexiantxendom0-3.2.10.git] / arch / x86 / kernel / process_64.c
index 442e7bf..733ca39 100644 (file)
@@ -14,7 +14,6 @@
  * This file handles the architecture-dependent parts of process handling..
  */
 
-#include <linux/stackprotector.h>
 #include <linux/cpu.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/notifier.h>
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
-#include <linux/tick.h>
 #include <linux/prctl.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/ftrace.h>
-#include <linux/cpuidle.h>
 
 #include <asm/pgtable.h>
-#include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/i387.h>
+#include <asm/fpu-internal.h>
 #include <asm/mmu_context.h>
 #include <asm/prctl.h>
 #include <asm/desc.h>
 #include <asm/idle.h>
 #include <asm/syscalls.h>
 #include <asm/debugreg.h>
-#include <asm/nmi.h>
+#include <asm/switch_to.h>
 
 asmlinkage extern void ret_from_fork(void);
 
 DEFINE_PER_CPU(unsigned long, old_rsp);
-static DEFINE_PER_CPU(unsigned char, is_idle);
-
-static ATOMIC_NOTIFIER_HEAD(idle_notifier);
-
-void idle_notifier_register(struct notifier_block *n)
-{
-       atomic_notifier_chain_register(&idle_notifier, n);
-}
-EXPORT_SYMBOL_GPL(idle_notifier_register);
-
-void idle_notifier_unregister(struct notifier_block *n)
-{
-       atomic_notifier_chain_unregister(&idle_notifier, n);
-}
-EXPORT_SYMBOL_GPL(idle_notifier_unregister);
-
-void enter_idle(void)
-{
-       percpu_write(is_idle, 1);
-       atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL);
-}
-
-static void __exit_idle(void)
-{
-       if (x86_test_and_clear_bit_percpu(0, is_idle) == 0)
-               return;
-       atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL);
-}
-
-/* Called from interrupts to signify idle end */
-void exit_idle(void)
-{
-       /* idle loop has pid 0 */
-       if (current->pid)
-               return;
-       __exit_idle();
-}
-
-#ifndef CONFIG_SMP
-static inline void play_dead(void)
-{
-       BUG();
-}
-#endif
-
-/*
- * 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)
-{
-       current_thread_info()->status |= TS_POLLING;
-
-       /*
-        * If we're the non-boot CPU, nothing set the stack canary up
-        * for us.  CPU0 already has it initialized but no harm in
-        * doing it again.  This is a good place for updating it, as
-        * we wont ever return from this function (so the invalid
-        * canaries already on the stack wont ever trigger).
-        */
-       boot_init_stack_canary();
-
-       /* endless idle loop with no priority at all */
-       while (1) {
-               tick_nohz_idle_enter();
-               while (!need_resched()) {
-
-                       rmb();
-
-                       if (cpu_is_offline(smp_processor_id()))
-                               play_dead();
-                       /*
-                        * Idle routines should keep interrupts disabled
-                        * from here on, until they go to idle.
-                        * Otherwise, idle callbacks can misfire.
-                        */
-                       local_touch_nmi();
-                       local_irq_disable();
-                       enter_idle();
-                       /* Don't trace irqs off for idle */
-                       stop_critical_timings();
-
-                       /* enter_idle() needs rcu for notifiers */
-                       rcu_idle_enter();
-
-                       if (cpuidle_idle_call())
-                               pm_idle();
-
-                       rcu_idle_exit();
-                       start_critical_timings();
-
-                       /* In many cases the interrupt that ended idle
-                          has already called exit_idle. But some idle
-                          loops can be woken up without interrupt. */
-                       __exit_idle();
-               }
-
-               tick_nohz_idle_exit();
-               schedule_preempt_disabled();
-       }
-}
 
 /* Prints also some state that isn't saved in the pt_regs */
 void __show_regs(struct pt_regs *regs, int all)
@@ -364,7 +258,9 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
 void start_thread_ia32(struct pt_regs *regs, u32 new_ip, u32 new_sp)
 {
        start_thread_common(regs, new_ip, new_sp,
-                           __USER32_CS, __USER32_DS, __USER32_DS);
+                           test_thread_flag(TIF_X32)
+                           ? __USER_CS : __USER32_CS,
+                           __USER_DS, __USER_DS);
 }
 #endif
 
@@ -487,6 +383,8 @@ void set_personality_64bit(void)
 
        /* Make sure to be in 64bit mode */
        clear_thread_flag(TIF_IA32);
+       clear_thread_flag(TIF_ADDR32);
+       clear_thread_flag(TIF_X32);
 
        /* Ensure the corresponding mm is not marked. */
        if (current->mm)
@@ -499,20 +397,31 @@ void set_personality_64bit(void)
        current->personality &= ~READ_IMPLIES_EXEC;
 }
 
-void set_personality_ia32(void)
+void set_personality_ia32(bool x32)
 {
        /* inherit personality from parent */
 
        /* Make sure to be in 32bit mode */
-       set_thread_flag(TIF_IA32);
-       current->personality |= force_personality32;
+       set_thread_flag(TIF_ADDR32);
 
        /* Mark the associated mm as containing 32-bit tasks. */
        if (current->mm)
                current->mm->context.ia32_compat = 1;
 
-       /* Prepare the first "return" to user space */
-       current_thread_info()->status |= TS_COMPAT;
+       if (x32) {
+               clear_thread_flag(TIF_IA32);
+               set_thread_flag(TIF_X32);
+               current->personality &= ~READ_IMPLIES_EXEC;
+               /* is_compat_task() uses the presence of the x32
+                  syscall bit flag to determine compat status */
+               current_thread_info()->status &= ~TS_COMPAT;
+       } else {
+               set_thread_flag(TIF_IA32);
+               clear_thread_flag(TIF_X32);
+               current->personality |= force_personality32;
+               /* Prepare the first "return" to user space */
+               current_thread_info()->status |= TS_COMPAT;
+       }
 }
 
 unsigned long get_wchan(struct task_struct *p)