]> pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'linus' into x86/pebs
authorIngo Molnar <mingo@elte.hu>
Fri, 25 Jul 2008 09:37:07 +0000 (11:37 +0200)
committerIngo Molnar <mingo@elte.hu>
Fri, 25 Jul 2008 09:37:07 +0000 (11:37 +0200)
Conflicts:

arch/x86/Kconfig.cpu
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/setup_64.c

Signed-off-by: Ingo Molnar <mingo@elte.hu>
1  2 
arch/x86/Kconfig.cpu
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/ptrace.c
include/asm-x86/processor.h
include/asm-x86/ptrace-abi.h
include/asm-x86/ptrace.h

diff --combined arch/x86/Kconfig.cpu
index 13f3f8bebfd16aec70c3df16c9ae966c9bcc1e2a,2c518fbc52ece13221e587ee71f11c81a4d5cec7..468ffc2df0e00bd9de97fc8472666070e1a8efc6
@@@ -344,7 -344,7 +344,7 @@@ config X86_F00F_BU
  
  config X86_WP_WORKS_OK
        def_bool y
-       depends on X86_32 && !M386
+       depends on !M386
  
  config X86_INVLPG
        def_bool y
@@@ -362,10 -362,6 +362,6 @@@ config X86_ALIGNMENT_1
        def_bool y
        depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1
  
- config X86_GOOD_APIC
-       def_bool y
-       depends on MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || MK8 || MEFFICEON || MCORE2 || MVIAC7 || X86_64
  config X86_INTEL_USERCOPY
        def_bool y
        depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK7 || MEFFICEON || MCORE2
@@@ -399,6 -395,10 +395,10 @@@ config X86_TS
        def_bool y
        depends on ((MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ) || X86_64
  
+ config X86_CMPXCHG64
+       def_bool y
+       depends on X86_PAE || X86_64
  # this should be set for all -march=.. options where the compiler
  # generates cmov.
  config X86_CMOV
@@@ -414,22 -414,4 +414,22 @@@ config X86_MINIMUM_CPU_FAMIL
  
  config X86_DEBUGCTLMSR
        def_bool y
-       depends on !(M586MMX || M586TSC || M586 || M486 || M386)
+       depends on !(MK6 || MWINCHIPC6 || MWINCHIP2 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386)
 +
 +config X86_DS
 +      bool "Debug Store support"
 +      default y
 +      help
 +        Add support for Debug Store.
 +        This allows the kernel to provide a memory buffer to the hardware
 +        to store various profiling and tracing events.
 +
 +config X86_PTRACE_BTS
 +      bool "ptrace interface to Branch Trace Store"
 +      default y
 +      depends on (X86_DS && X86_DEBUGCTLMSR)
 +      help
 +        Add a ptrace interface to allow collecting an execution trace
 +        of the traced task.
 +        This collects control flow changes in a (cyclic) buffer and allows
 +        debuggers to fill in the gaps and show an execution trace of the debuggee.
index cbffa2a25a1334e53a7e65f637da6e647d182aba,b75f2569b8f8ba1940d55ce3616f25a91c7c6d75..f113ef4595f6ca81dd810058337f4118590083b3
@@@ -222,11 -222,24 +222,25 @@@ static void __cpuinit init_intel(struc
                        set_cpu_cap(c, X86_FEATURE_BTS);
                if (!(l1 & (1<<12)))
                        set_cpu_cap(c, X86_FEATURE_PEBS);
 +              ds_init_intel(c);
        }
  
        if (cpu_has_bts)
 -              ds_init_intel(c);
 +              ptrace_bts_init_intel(c);
+       /*
+        * See if we have a good local APIC by checking for buggy Pentia,
+        * i.e. all B steppings and the C2 stepping of P54C when using their
+        * integrated APIC (see 11AP erratum in "Pentium Processor
+        * Specification Update").
+        */
+       if (cpu_has_apic && (c->x86<<8 | c->x86_model<<4) == 0x520 &&
+           (c->x86_mask < 0x6 || c->x86_mask == 0xb))
+               set_cpu_cap(c, X86_FEATURE_11AP);
+ #ifdef CONFIG_X86_NUMAQ
+       numaq_tsc_disable();
+ #endif
  }
  
  static unsigned int __cpuinit intel_size_cache(struct cpuinfo_x86 *c, unsigned int size)
index b105c559a073b23f67e8d44f1974185119a5632d,53bc653ed5ca52bab902dde3d9efbc0e1630eb6c..68f4ae2ac99a0664e2b0e2679f0b0172bae4011a
  
  asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
  
- static int hlt_counter;
- unsigned long boot_option_idle_override = 0;
- EXPORT_SYMBOL(boot_option_idle_override);
  DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task;
  EXPORT_PER_CPU_SYMBOL(current_task);
  
@@@ -77,57 -72,24 +72,24 @@@ unsigned long thread_saved_pc(struct ta
        return ((unsigned long *)tsk->thread.sp)[3];
  }
  
- /*
-  * Powermanagement idle function, if any..
-  */
- void (*pm_idle)(void);
- EXPORT_SYMBOL(pm_idle);
+ #ifdef CONFIG_HOTPLUG_CPU
+ #include <asm/nmi.h>
  
void disable_hlt(void)
static void cpu_exit_clear(void)
  {
-       hlt_counter++;
- }
+       int cpu = raw_smp_processor_id();
  
EXPORT_SYMBOL(disable_hlt);
      idle_task_exit();
  
- void enable_hlt(void)
- {
-       hlt_counter--;
- }
+       cpu_uninit();
+       irq_ctx_exit(cpu);
  
- EXPORT_SYMBOL(enable_hlt);
+       cpu_clear(cpu, cpu_callout_map);
+       cpu_clear(cpu, cpu_callin_map);
  
- /*
-  * We use this if we don't have any better
-  * idle routine..
-  */
- void default_idle(void)
- {
-       if (!hlt_counter && boot_cpu_data.hlt_works_ok) {
-               current_thread_info()->status &= ~TS_POLLING;
-               /*
-                * TS_POLLING-cleared state must be visible before we
-                * test NEED_RESCHED:
-                */
-               smp_mb();
-               if (!need_resched())
-                       safe_halt();    /* enables interrupts racelessly */
-               else
-                       local_irq_enable();
-               current_thread_info()->status |= TS_POLLING;
-       } else {
-               local_irq_enable();
-               /* loop is done by the caller */
-               cpu_relax();
-       }
+       numa_remove_cpu(cpu);
  }
- #ifdef CONFIG_APM_MODULE
- EXPORT_SYMBOL(default_idle);
- #endif
  
- #ifdef CONFIG_HOTPLUG_CPU
- #include <asm/nmi.h>
  /* We don't actually take CPU down, just spin without interrupts. */
  static inline void play_dead(void)
  {
@@@ -166,26 -128,24 +128,24 @@@ void cpu_idle(void
  
        /* endless idle loop with no priority at all */
        while (1) {
-               tick_nohz_stop_sched_tick();
+               tick_nohz_stop_sched_tick(1);
                while (!need_resched()) {
-                       void (*idle)(void);
  
                        check_pgt_cache();
                        rmb();
-                       idle = pm_idle;
  
                        if (rcu_pending(cpu))
                                rcu_check_callbacks(cpu, 0);
  
-                       if (!idle)
-                               idle = default_idle;
                        if (cpu_is_offline(cpu))
                                play_dead();
  
                        local_irq_disable();
                        __get_cpu_var(irq_stat).idle_timestamp = jiffies;
-                       idle();
+                       /* Don't trace irqs off for idle */
+                       stop_critical_timings();
+                       pm_idle();
+                       start_critical_timings();
                }
                tick_nohz_restart_sched_tick();
                preempt_enable_no_resched();
@@@ -316,14 -276,6 +276,14 @@@ void exit_thread(void
                tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
                put_cpu();
        }
 +#ifdef CONFIG_X86_DS
 +      /* Free any DS contexts that have not been properly released. */
 +      if (unlikely(current->thread.ds_ctx)) {
 +              /* we clear debugctl to make sure DS is not used. */
 +              update_debugctlmsr(0);
 +              ds_free(current->thread.ds_ctx);
 +      }
 +#endif /* CONFIG_X86_DS */
  }
  
  void flush_thread(void)
@@@ -485,35 -437,6 +445,35 @@@ int set_tsc_mode(unsigned int val
        return 0;
  }
  
 +#ifdef CONFIG_X86_DS
 +static int update_debugctl(struct thread_struct *prev,
 +                      struct thread_struct *next, unsigned long debugctl)
 +{
 +      unsigned long ds_prev = 0;
 +      unsigned long ds_next = 0;
 +
 +      if (prev->ds_ctx)
 +              ds_prev = (unsigned long)prev->ds_ctx->ds;
 +      if (next->ds_ctx)
 +              ds_next = (unsigned long)next->ds_ctx->ds;
 +
 +      if (ds_next != ds_prev) {
 +              /* we clear debugctl to make sure DS
 +               * is not in use when we change it */
 +              debugctl = 0;
 +              update_debugctlmsr(0);
 +              wrmsr(MSR_IA32_DS_AREA, ds_next, 0);
 +      }
 +      return debugctl;
 +}
 +#else
 +static int update_debugctl(struct thread_struct *prev,
 +                      struct thread_struct *next, unsigned long debugctl)
 +{
 +      return debugctl;
 +}
 +#endif /* CONFIG_X86_DS */
 +
  static noinline void
  __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
                 struct tss_struct *tss)
        prev = &prev_p->thread;
        next = &next_p->thread;
  
 -      debugctl = prev->debugctlmsr;
 -      if (next->ds_area_msr != prev->ds_area_msr) {
 -              /* we clear debugctl to make sure DS
 -               * is not in use when we change it */
 -              debugctl = 0;
 -              update_debugctlmsr(0);
 -              wrmsr(MSR_IA32_DS_AREA, next->ds_area_msr, 0);
 -      }
 +      debugctl = update_debugctl(prev, next, prev->debugctlmsr);
  
        if (next->debugctlmsr != debugctl)
                update_debugctlmsr(next->debugctlmsr);
                        hard_enable_TSC();
        }
  
 -#ifdef X86_BTS
 +#ifdef CONFIG_X86_PTRACE_BTS
        if (test_tsk_thread_flag(prev_p, TIF_BTS_TRACE_TS))
                ptrace_bts_take_timestamp(prev_p, BTS_TASK_DEPARTS);
  
        if (test_tsk_thread_flag(next_p, TIF_BTS_TRACE_TS))
                ptrace_bts_take_timestamp(next_p, BTS_TASK_ARRIVES);
 -#endif
 +#endif /* CONFIG_X86_PTRACE_BTS */
  
  
        if (!test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) {
index a4ad0d7ea621be0db78fc32d21c0a2a214a82d9f,3fb62a7d9a16250092a9827a66af062be4824513..91ffce47af8ec5401e8be094b39774f8dc843c57
@@@ -56,15 -56,6 +56,6 @@@ asmlinkage extern void ret_from_fork(vo
  
  unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED;
  
- unsigned long boot_option_idle_override = 0;
- EXPORT_SYMBOL(boot_option_idle_override);
- /*
-  * Powermanagement idle function, if any..
-  */
- void (*pm_idle)(void);
- EXPORT_SYMBOL(pm_idle);
  static ATOMIC_NOTIFIER_HEAD(idle_notifier);
  
  void idle_notifier_register(struct notifier_block *n)
@@@ -94,25 -85,6 +85,6 @@@ void exit_idle(void
        __exit_idle();
  }
  
- /*
-  * We use this if we don't have any better
-  * idle routine..
-  */
- void default_idle(void)
- {
-       current_thread_info()->status &= ~TS_POLLING;
-       /*
-        * TS_POLLING-cleared state must be visible before we
-        * test NEED_RESCHED:
-        */
-       smp_mb();
-       if (!need_resched())
-               safe_halt();    /* enables interrupts racelessly */
-       else
-               local_irq_enable();
-       current_thread_info()->status |= TS_POLLING;
- }
  #ifdef CONFIG_HOTPLUG_CPU
  DECLARE_PER_CPU(int, cpu_state);
  
@@@ -148,14 -120,11 +120,11 @@@ void cpu_idle(void
        current_thread_info()->status |= TS_POLLING;
        /* endless idle loop with no priority at all */
        while (1) {
-               tick_nohz_stop_sched_tick();
+               tick_nohz_stop_sched_tick(1);
                while (!need_resched()) {
-                       void (*idle)(void);
  
                        rmb();
-                       idle = pm_idle;
-                       if (!idle)
-                               idle = default_idle;
                        if (cpu_is_offline(smp_processor_id()))
                                play_dead();
                        /*
                         */
                        local_irq_disable();
                        enter_idle();
-                       idle();
+                       /* Don't trace irqs off for idle */
+                       stop_critical_timings();
+                       pm_idle();
+                       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. */
@@@ -267,14 -239,6 +239,14 @@@ void exit_thread(void
                t->io_bitmap_max = 0;
                put_cpu();
        }
 +#ifdef CONFIG_X86_DS
 +      /* Free any DS contexts that have not been properly released. */
 +      if (unlikely(t->ds_ctx)) {
 +              /* we clear debugctl to make sure DS is not used. */
 +              update_debugctlmsr(0);
 +              ds_free(t->ds_ctx);
 +      }
 +#endif /* CONFIG_X86_DS */
  }
  
  void flush_thread(void)
@@@ -374,10 -338,10 +346,10 @@@ int copy_thread(int nr, unsigned long c
        p->thread.fs = me->thread.fs;
        p->thread.gs = me->thread.gs;
  
-       asm("mov %%gs,%0" : "=m" (p->thread.gsindex));
-       asm("mov %%fs,%0" : "=m" (p->thread.fsindex));
-       asm("mov %%es,%0" : "=m" (p->thread.es));
-       asm("mov %%ds,%0" : "=m" (p->thread.ds));
+       savesegment(gs, p->thread.gsindex);
+       savesegment(fs, p->thread.fsindex);
+       savesegment(es, p->thread.es);
+       savesegment(ds, p->thread.ds);
  
        if (unlikely(test_tsk_thread_flag(me, TIF_IO_BITMAP))) {
                p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
@@@ -416,7 -380,9 +388,9 @@@ out
  void
  start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
  {
-       asm volatile("movl %0, %%fs; movl %0, %%es; movl %0, %%ds" :: "r"(0));
+       loadsegment(fs, 0);
+       loadsegment(es, 0);
+       loadsegment(ds, 0);
        load_gs_index(0);
        regs->ip                = new_ip;
        regs->sp                = new_sp;
@@@ -506,27 -472,13 +480,27 @@@ static inline void __switch_to_xtra(str
        next = &next_p->thread;
  
        debugctl = prev->debugctlmsr;
 -      if (next->ds_area_msr != prev->ds_area_msr) {
 -              /* we clear debugctl to make sure DS
 -               * is not in use when we change it */
 -              debugctl = 0;
 -              update_debugctlmsr(0);
 -              wrmsrl(MSR_IA32_DS_AREA, next->ds_area_msr);
 +
 +#ifdef CONFIG_X86_DS
 +      {
 +              unsigned long ds_prev = 0, ds_next = 0;
 +
 +              if (prev->ds_ctx)
 +                      ds_prev = (unsigned long)prev->ds_ctx->ds;
 +              if (next->ds_ctx)
 +                      ds_next = (unsigned long)next->ds_ctx->ds;
 +
 +              if (ds_next != ds_prev) {
 +                      /*
 +                       * We clear debugctl to make sure DS
 +                       * is not in use when we change it:
 +                       */
 +                      debugctl = 0;
 +                      update_debugctlmsr(0);
 +                      wrmsrl(MSR_IA32_DS_AREA, ds_next);
 +              }
        }
 +#endif /* CONFIG_X86_DS */
  
        if (next->debugctlmsr != debugctl)
                update_debugctlmsr(next->debugctlmsr);
                memset(tss->io_bitmap, 0xff, prev->io_bitmap_max);
        }
  
 -#ifdef X86_BTS
 +#ifdef CONFIG_X86_PTRACE_BTS
        if (test_tsk_thread_flag(prev_p, TIF_BTS_TRACE_TS))
                ptrace_bts_take_timestamp(prev_p, BTS_TASK_DEPARTS);
  
        if (test_tsk_thread_flag(next_p, TIF_BTS_TRACE_TS))
                ptrace_bts_take_timestamp(next_p, BTS_TASK_ARRIVES);
 -#endif
 +#endif /* CONFIG_X86_PTRACE_BTS */
  }
  
  /*
  struct task_struct *
  __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
  {
-       struct thread_struct *prev = &prev_p->thread,
-                                *next = &next_p->thread;
+       struct thread_struct *prev = &prev_p->thread;
+       struct thread_struct *next = &next_p->thread;
        int cpu = smp_processor_id();
        struct tss_struct *tss = &per_cpu(init_tss, cpu);
+       unsigned fsindex, gsindex;
  
        /* we're going to use this soon, after a few expensive things */
        if (next_p->fpu_counter>5)
         * Switch DS and ES.
         * This won't pick up thread selector changes, but I guess that is ok.
         */
-       asm volatile("mov %%es,%0" : "=m" (prev->es));
+       savesegment(es, prev->es);
        if (unlikely(next->es | prev->es))
                loadsegment(es, next->es); 
-       
-       asm volatile ("mov %%ds,%0" : "=m" (prev->ds));
+       savesegment(ds, prev->ds);
        if (unlikely(next->ds | prev->ds))
                loadsegment(ds, next->ds);
  
+       /* We must save %fs and %gs before load_TLS() because
+        * %fs and %gs may be cleared by load_TLS().
+        *
+        * (e.g. xen_load_tls())
+        */
+       savesegment(fs, fsindex);
+       savesegment(gs, gsindex);
        load_TLS(next, cpu);
  
+       /*
+        * Leave lazy mode, flushing any hypercalls made here.
+        * This must be done before restoring TLS segments so
+        * the GDT and LDT are properly updated, and must be
+        * done before math_state_restore, so the TS bit is up
+        * to date.
+        */
+       arch_leave_lazy_cpu_mode();
        /* 
         * Switch FS and GS.
+        *
+        * Segment register != 0 always requires a reload.  Also
+        * reload when it has changed.  When prev process used 64bit
+        * base always reload to avoid an information leak.
         */
-       { 
-               unsigned fsindex;
-               asm volatile("movl %%fs,%0" : "=r" (fsindex)); 
-               /* segment register != 0 always requires a reload. 
-                  also reload when it has changed. 
-                  when prev process used 64bit base always reload
-                  to avoid an information leak. */
-               if (unlikely(fsindex | next->fsindex | prev->fs)) {
-                       loadsegment(fs, next->fsindex);
-                       /* check if the user used a selector != 0
-                        * if yes clear 64bit base, since overloaded base
-                          * is always mapped to the Null selector
-                          */
-                       if (fsindex)
+       if (unlikely(fsindex | next->fsindex | prev->fs)) {
+               loadsegment(fs, next->fsindex);
+               /* 
+                * Check if the user used a selector != 0; if yes
+                *  clear 64bit base, since overloaded base is always
+                *  mapped to the Null selector
+                */
+               if (fsindex)
                        prev->fs = 0;                           
-               }
-               /* when next process has a 64bit base use it */
-               if (next->fs) 
-                       wrmsrl(MSR_FS_BASE, next->fs); 
-               prev->fsindex = fsindex;
        }
-       { 
-               unsigned gsindex;
-               asm volatile("movl %%gs,%0" : "=r" (gsindex)); 
-               if (unlikely(gsindex | next->gsindex | prev->gs)) {
-                       load_gs_index(next->gsindex);
-                       if (gsindex)
+       /* when next process has a 64bit base use it */
+       if (next->fs)
+               wrmsrl(MSR_FS_BASE, next->fs);
+       prev->fsindex = fsindex;
+       if (unlikely(gsindex | next->gsindex | prev->gs)) {
+               load_gs_index(next->gsindex);
+               if (gsindex)
                        prev->gs = 0;                           
-               }
-               if (next->gs)
-                       wrmsrl(MSR_KERNEL_GS_BASE, next->gs); 
-               prev->gsindex = gsindex;
        }
+       if (next->gs)
+               wrmsrl(MSR_KERNEL_GS_BASE, next->gs);
+       prev->gsindex = gsindex;
  
        /* Must be after DS reload */
        unlazy_fpu(prev_p);
        write_pda(pcurrent, next_p); 
  
        write_pda(kernelstack,
-       (unsigned long)task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET);
+                 (unsigned long)task_stack_page(next_p) +
+                 THREAD_SIZE - PDA_STACKOFFSET);
  #ifdef CONFIG_CC_STACKPROTECTOR
        write_pda(stack_canary, next_p->stack_canary);
        /*
@@@ -820,7 -786,7 +808,7 @@@ long do_arch_prctl(struct task_struct *
                        set_32bit_tls(task, FS_TLS, addr);
                        if (doit) {
                                load_TLS(&task->thread, cpu);
-                               asm volatile("movl %0,%%fs" :: "r"(FS_TLS_SEL));
+                               loadsegment(fs, FS_TLS_SEL);
                        }
                        task->thread.fsindex = FS_TLS_SEL;
                        task->thread.fs = 0;
                        if (doit) {
                                /* set the selector to 0 to not confuse
                                   __switch_to */
-                               asm volatile("movl %0,%%fs" :: "r" (0));
+                               loadsegment(fs, 0);
                                ret = checking_wrmsrl(MSR_FS_BASE, addr);
                        }
                }
                if (task->thread.gsindex == GS_TLS_SEL)
                        base = read_32bit_tls(task, GS_TLS);
                else if (doit) {
-                       asm("movl %%gs,%0" : "=r" (gsindex));
+                       savesegment(gs, gsindex);
                        if (gsindex)
                                rdmsrl(MSR_KERNEL_GS_BASE, base);
                        else
diff --combined arch/x86/kernel/ptrace.c
index 170f0932f70f453a8b98fdeb9ffc6483ed2fade1,e37dccce85db5e15922602b833a3821b78ca4ffd..ba19bb49bd097584239853ecdd220fd6c9d5e3aa
@@@ -554,115 -554,45 +554,115 @@@ static int ptrace_set_debugreg(struct t
        return 0;
  }
  
 -#ifdef X86_BTS
 +#ifdef CONFIG_X86_PTRACE_BTS
 +/*
 + * The configuration for a particular BTS hardware implementation.
 + */
 +struct bts_configuration {
 +      /* the size of a BTS record in bytes; at most BTS_MAX_RECORD_SIZE */
 +      unsigned char  sizeof_bts;
 +      /* the size of a field in the BTS record in bytes */
 +      unsigned char  sizeof_field;
 +      /* a bitmask to enable/disable BTS in DEBUGCTL MSR */
 +      unsigned long debugctl_mask;
 +};
 +static struct bts_configuration bts_cfg;
 +
 +#define BTS_MAX_RECORD_SIZE (8 * 3)
 +
 +
 +/*
 + * Branch Trace Store (BTS) uses the following format. Different
 + * architectures vary in the size of those fields.
 + * - source linear address
 + * - destination linear address
 + * - flags
 + *
 + * Later architectures use 64bit pointers throughout, whereas earlier
 + * architectures use 32bit pointers in 32bit mode.
 + *
 + * We compute the base address for the first 8 fields based on:
 + * - the field size stored in the DS configuration
 + * - the relative field position
 + *
 + * In order to store additional information in the BTS buffer, we use
 + * a special source address to indicate that the record requires
 + * special interpretation.
 + *
 + * Netburst indicated via a bit in the flags field whether the branch
 + * was predicted; this is ignored.
 + */
 +
 +enum bts_field {
 +      bts_from = 0,
 +      bts_to,
 +      bts_flags,
 +
 +      bts_escape = (unsigned long)-1,
 +      bts_qual = bts_to,
 +      bts_jiffies = bts_flags
 +};
  
 -static int ptrace_bts_get_size(struct task_struct *child)
 +static inline unsigned long bts_get(const char *base, enum bts_field field)
  {
 -      if (!child->thread.ds_area_msr)
 -              return -ENXIO;
 +      base += (bts_cfg.sizeof_field * field);
 +      return *(unsigned long *)base;
 +}
 +
 +static inline void bts_set(char *base, enum bts_field field, unsigned long val)
 +{
 +      base += (bts_cfg.sizeof_field * field);;
 +      (*(unsigned long *)base) = val;
 +}
  
 -      return ds_get_bts_index((void *)child->thread.ds_area_msr);
 +/*
 + * Translate a BTS record from the raw format into the bts_struct format
 + *
 + * out (out): bts_struct interpretation
 + * raw: raw BTS record
 + */
 +static void ptrace_bts_translate_record(struct bts_struct *out, const void *raw)
 +{
 +      memset(out, 0, sizeof(*out));
 +      if (bts_get(raw, bts_from) == bts_escape) {
 +              out->qualifier       = bts_get(raw, bts_qual);
 +              out->variant.jiffies = bts_get(raw, bts_jiffies);
 +      } else {
 +              out->qualifier = BTS_BRANCH;
 +              out->variant.lbr.from_ip = bts_get(raw, bts_from);
 +              out->variant.lbr.to_ip   = bts_get(raw, bts_to);
 +      }
  }
  
 -static int ptrace_bts_read_record(struct task_struct *child,
 -                                long index,
 +static int ptrace_bts_read_record(struct task_struct *child, size_t index,
                                  struct bts_struct __user *out)
  {
        struct bts_struct ret;
 -      int retval;
 -      int bts_end;
 -      int bts_index;
 +      const void *bts_record;
 +      size_t bts_index, bts_end;
 +      int error;
  
 -      if (!child->thread.ds_area_msr)
 -              return -ENXIO;
 +      error = ds_get_bts_end(child, &bts_end);
 +      if (error < 0)
 +              return error;
  
 -      if (index < 0)
 -              return -EINVAL;
 -
 -      bts_end = ds_get_bts_end((void *)child->thread.ds_area_msr);
        if (bts_end <= index)
                return -EINVAL;
  
 +      error = ds_get_bts_index(child, &bts_index);
 +      if (error < 0)
 +              return error;
 +
        /* translate the ptrace bts index into the ds bts index */
 -      bts_index = ds_get_bts_index((void *)child->thread.ds_area_msr);
 -      bts_index -= (index + 1);
 -      if (bts_index < 0)
 -              bts_index += bts_end;
 +      bts_index += bts_end - (index + 1);
 +      if (bts_end <= bts_index)
 +              bts_index -= bts_end;
 +
 +      error = ds_access_bts(child, bts_index, &bts_record);
 +      if (error < 0)
 +              return error;
  
 -      retval = ds_read_bts((void *)child->thread.ds_area_msr,
 -                           bts_index, &ret);
 -      if (retval < 0)
 -              return retval;
 +      ptrace_bts_translate_record(&ret, bts_record);
  
        if (copy_to_user(out, &ret, sizeof(ret)))
                return -EFAULT;
        return sizeof(ret);
  }
  
 -static int ptrace_bts_clear(struct task_struct *child)
 -{
 -      if (!child->thread.ds_area_msr)
 -              return -ENXIO;
 -
 -      return ds_clear((void *)child->thread.ds_area_msr);
 -}
 -
  static int ptrace_bts_drain(struct task_struct *child,
                            long size,
                            struct bts_struct __user *out)
  {
 -      int end, i;
 -      void *ds = (void *)child->thread.ds_area_msr;
 -
 -      if (!ds)
 -              return -ENXIO;
 +      struct bts_struct ret;
 +      const unsigned char *raw;
 +      size_t end, i;
 +      int error;
  
 -      end = ds_get_bts_index(ds);
 -      if (end <= 0)
 -              return end;
 +      error = ds_get_bts_index(child, &end);
 +      if (error < 0)
 +              return error;
  
        if (size < (end * sizeof(struct bts_struct)))
                return -EIO;
  
 -      for (i = 0; i < end; i++, out++) {
 -              struct bts_struct ret;
 -              int retval;
 +      error = ds_access_bts(child, 0, (const void **)&raw);
 +      if (error < 0)
 +              return error;
  
 -              retval = ds_read_bts(ds, i, &ret);
 -              if (retval < 0)
 -                      return retval;
 +      for (i = 0; i < end; i++, out++, raw += bts_cfg.sizeof_bts) {
 +              ptrace_bts_translate_record(&ret, raw);
  
                if (copy_to_user(out, &ret, sizeof(ret)))
                        return -EFAULT;
        }
  
 -      ds_clear(ds);
 +      error = ds_clear_bts(child);
 +      if (error < 0)
 +              return error;
  
        return end;
  }
  
 +static void ptrace_bts_ovfl(struct task_struct *child)
 +{
 +      send_sig(child->thread.bts_ovfl_signal, child, 0);
 +}
 +
  static int ptrace_bts_config(struct task_struct *child,
                             long cfg_size,
                             const struct ptrace_bts_config __user *ucfg)
  {
        struct ptrace_bts_config cfg;
 -      int bts_size, ret = 0;
 -      void *ds;
 +      int error = 0;
 +
 +      error = -EOPNOTSUPP;
 +      if (!bts_cfg.sizeof_bts)
 +              goto errout;
  
 +      error = -EIO;
        if (cfg_size < sizeof(cfg))
 -              return -EIO;
 +              goto errout;
  
 +      error = -EFAULT;
        if (copy_from_user(&cfg, ucfg, sizeof(cfg)))
 -              return -EFAULT;
 +              goto errout;
  
 -      if ((int)cfg.size < 0)
 -              return -EINVAL;
 +      error = -EINVAL;
 +      if ((cfg.flags & PTRACE_BTS_O_SIGNAL) &&
 +          !(cfg.flags & PTRACE_BTS_O_ALLOC))
 +              goto errout;
  
 -      bts_size = 0;
 -      ds = (void *)child->thread.ds_area_msr;
 -      if (ds) {
 -              bts_size = ds_get_bts_size(ds);
 -              if (bts_size < 0)
 -                      return bts_size;
 -      }
 -      cfg.size = PAGE_ALIGN(cfg.size);
 +      if (cfg.flags & PTRACE_BTS_O_ALLOC) {
 +              ds_ovfl_callback_t ovfl = 0;
 +              unsigned int sig = 0;
 +
 +              /* we ignore the error in case we were not tracing child */
 +              (void)ds_release_bts(child);
 +
 +              if (cfg.flags & PTRACE_BTS_O_SIGNAL) {
 +                      if (!cfg.signal)
 +                              goto errout;
 +
 +                      sig  = cfg.signal;
 +                      ovfl = ptrace_bts_ovfl;
 +              }
  
 -      if (bts_size != cfg.size) {
 -              ret = ptrace_bts_realloc(child, cfg.size,
 -                                       cfg.flags & PTRACE_BTS_O_CUT_SIZE);
 -              if (ret < 0)
 +              error = ds_request_bts(child, /* base = */ 0, cfg.size, ovfl);
 +              if (error < 0)
                        goto errout;
  
 -              ds = (void *)child->thread.ds_area_msr;
 +              child->thread.bts_ovfl_signal = sig;
        }
  
 -      if (cfg.flags & PTRACE_BTS_O_SIGNAL)
 -              ret = ds_set_overflow(ds, DS_O_SIGNAL);
 -      else
 -              ret = ds_set_overflow(ds, DS_O_WRAP);
 -      if (ret < 0)
 +      error = -EINVAL;
 +      if (!child->thread.ds_ctx && cfg.flags)
                goto errout;
  
        if (cfg.flags & PTRACE_BTS_O_TRACE)
 -              child->thread.debugctlmsr |= ds_debugctl_mask();
 +              child->thread.debugctlmsr |= bts_cfg.debugctl_mask;
        else
 -              child->thread.debugctlmsr &= ~ds_debugctl_mask();
 +              child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask;
  
        if (cfg.flags & PTRACE_BTS_O_SCHED)
                set_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
        else
                clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
  
 -      ret = sizeof(cfg);
 +      error = sizeof(cfg);
  
  out:
        if (child->thread.debugctlmsr)
        else
                clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
  
 -      return ret;
 +      return error;
  
  errout:
 -      child->thread.debugctlmsr &= ~ds_debugctl_mask();
 +      child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask;
        clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
        goto out;
  }
@@@ -789,40 -714,29 +789,40 @@@ static int ptrace_bts_status(struct tas
                             long cfg_size,
                             struct ptrace_bts_config __user *ucfg)
  {
 -      void *ds = (void *)child->thread.ds_area_msr;
        struct ptrace_bts_config cfg;
 +      size_t end;
 +      const void *base, *max;
 +      int error;
  
        if (cfg_size < sizeof(cfg))
                return -EIO;
  
 -      memset(&cfg, 0, sizeof(cfg));
 +      error = ds_get_bts_end(child, &end);
 +      if (error < 0)
 +              return error;
  
 -      if (ds) {
 -              cfg.size = ds_get_bts_size(ds);
 +      error = ds_access_bts(child, /* index = */ 0, &base);
 +      if (error < 0)
 +              return error;
  
 -              if (ds_get_overflow(ds) == DS_O_SIGNAL)
 -                      cfg.flags |= PTRACE_BTS_O_SIGNAL;
 +      error = ds_access_bts(child, /* index = */ end, &max);
 +      if (error < 0)
 +              return error;
  
 -              if (test_tsk_thread_flag(child, TIF_DEBUGCTLMSR) &&
 -                  child->thread.debugctlmsr & ds_debugctl_mask())
 -                      cfg.flags |= PTRACE_BTS_O_TRACE;
 +      memset(&cfg, 0, sizeof(cfg));
 +      cfg.size = (max - base);
 +      cfg.signal = child->thread.bts_ovfl_signal;
 +      cfg.bts_size = sizeof(struct bts_struct);
  
 -              if (test_tsk_thread_flag(child, TIF_BTS_TRACE_TS))
 -                      cfg.flags |= PTRACE_BTS_O_SCHED;
 -      }
 +      if (cfg.signal)
 +              cfg.flags |= PTRACE_BTS_O_SIGNAL;
  
 -      cfg.bts_size = sizeof(struct bts_struct);
 +      if (test_tsk_thread_flag(child, TIF_DEBUGCTLMSR) &&
 +          child->thread.debugctlmsr & bts_cfg.debugctl_mask)
 +              cfg.flags |= PTRACE_BTS_O_TRACE;
 +
 +      if (test_tsk_thread_flag(child, TIF_BTS_TRACE_TS))
 +              cfg.flags |= PTRACE_BTS_O_SCHED;
  
        if (copy_to_user(ucfg, &cfg, sizeof(cfg)))
                return -EFAULT;
        return sizeof(cfg);
  }
  
 -
  static int ptrace_bts_write_record(struct task_struct *child,
                                   const struct bts_struct *in)
  {
 -      int retval;
 +      unsigned char bts_record[BTS_MAX_RECORD_SIZE];
  
 -      if (!child->thread.ds_area_msr)
 -              return -ENXIO;
 +      BUG_ON(BTS_MAX_RECORD_SIZE < bts_cfg.sizeof_bts);
  
 -      retval = ds_write_bts((void *)child->thread.ds_area_msr, in);
 -      if (retval)
 -              return retval;
 +      memset(bts_record, 0, bts_cfg.sizeof_bts);
 +      switch (in->qualifier) {
 +      case BTS_INVALID:
 +              break;
  
 -      return sizeof(*in);
 -}
 +      case BTS_BRANCH:
 +              bts_set(bts_record, bts_from, in->variant.lbr.from_ip);
 +              bts_set(bts_record, bts_to,   in->variant.lbr.to_ip);
 +              break;
  
 -static int ptrace_bts_realloc(struct task_struct *child,
 -                            int size, int reduce_size)
 -{
 -      unsigned long rlim, vm;
 -      int ret, old_size;
 +      case BTS_TASK_ARRIVES:
 +      case BTS_TASK_DEPARTS:
 +              bts_set(bts_record, bts_from,    bts_escape);
 +              bts_set(bts_record, bts_qual,    in->qualifier);
 +              bts_set(bts_record, bts_jiffies, in->variant.jiffies);
 +              break;
  
 -      if (size < 0)
 +      default:
                return -EINVAL;
 -
 -      old_size = ds_get_bts_size((void *)child->thread.ds_area_msr);
 -      if (old_size < 0)
 -              return old_size;
 -
 -      ret = ds_free((void **)&child->thread.ds_area_msr);
 -      if (ret < 0)
 -              goto out;
 -
 -      size >>= PAGE_SHIFT;
 -      old_size >>= PAGE_SHIFT;
 -
 -      current->mm->total_vm  -= old_size;
 -      current->mm->locked_vm -= old_size;
 -
 -      if (size == 0)
 -              goto out;
 -
 -      rlim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
 -      vm = current->mm->total_vm  + size;
 -      if (rlim < vm) {
 -              ret = -ENOMEM;
 -
 -              if (!reduce_size)
 -                      goto out;
 -
 -              size = rlim - current->mm->total_vm;
 -              if (size <= 0)
 -                      goto out;
        }
  
 -      rlim = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
 -      vm = current->mm->locked_vm  + size;
 -      if (rlim < vm) {
 -              ret = -ENOMEM;
 -
 -              if (!reduce_size)
 -                      goto out;
 -
 -              size = rlim - current->mm->locked_vm;
 -              if (size <= 0)
 -                      goto out;
 -      }
 -
 -      ret = ds_allocate((void **)&child->thread.ds_area_msr,
 -                        size << PAGE_SHIFT);
 -      if (ret < 0)
 -              goto out;
 -
 -      current->mm->total_vm  += size;
 -      current->mm->locked_vm += size;
 -
 -out:
 -      if (child->thread.ds_area_msr)
 -              set_tsk_thread_flag(child, TIF_DS_AREA_MSR);
 -      else
 -              clear_tsk_thread_flag(child, TIF_DS_AREA_MSR);
 -
 -      return ret;
 +      /* The writing task will be the switched-to task on a context
 +       * switch. It needs to write into the switched-from task's BTS
 +       * buffer. */
 +      return ds_unchecked_write_bts(child, bts_record, bts_cfg.sizeof_bts);
  }
  
  void ptrace_bts_take_timestamp(struct task_struct *tsk,
  
        ptrace_bts_write_record(tsk, &rec);
  }
 -#endif /* X86_BTS */
 +
 +static const struct bts_configuration bts_cfg_netburst = {
 +      .sizeof_bts    = sizeof(long) * 3,
 +      .sizeof_field  = sizeof(long),
 +      .debugctl_mask = (1<<2)|(1<<3)|(1<<5)
 +};
 +
 +static const struct bts_configuration bts_cfg_pentium_m = {
 +      .sizeof_bts    = sizeof(long) * 3,
 +      .sizeof_field  = sizeof(long),
 +      .debugctl_mask = (1<<6)|(1<<7)
 +};
 +
 +static const struct bts_configuration bts_cfg_core2 = {
 +      .sizeof_bts    = 8 * 3,
 +      .sizeof_field  = 8,
 +      .debugctl_mask = (1<<6)|(1<<7)|(1<<9)
 +};
 +
 +static inline void bts_configure(const struct bts_configuration *cfg)
 +{
 +      bts_cfg = *cfg;
 +}
 +
 +void __cpuinit ptrace_bts_init_intel(struct cpuinfo_x86 *c)
 +{
 +      switch (c->x86) {
 +      case 0x6:
 +              switch (c->x86_model) {
 +              case 0xD:
 +              case 0xE: /* Pentium M */
 +                      bts_configure(&bts_cfg_pentium_m);
 +                      break;
 +              case 0xF: /* Core2 */
 +        case 0x1C: /* Atom */
 +                      bts_configure(&bts_cfg_core2);
 +                      break;
 +              default:
 +                      /* sorry, don't know about them */
 +                      break;
 +              }
 +              break;
 +      case 0xF:
 +              switch (c->x86_model) {
 +              case 0x0:
 +              case 0x1:
 +              case 0x2: /* Netburst */
 +                      bts_configure(&bts_cfg_netburst);
 +                      break;
 +              default:
 +                      /* sorry, don't know about them */
 +                      break;
 +              }
 +              break;
 +      default:
 +              /* sorry, don't know about them */
 +              break;
 +      }
 +}
 +#endif /* CONFIG_X86_PTRACE_BTS */
  
  /*
   * Called by kernel/ptrace.c when detaching..
@@@ -946,15 -852,15 +946,15 @@@ void ptrace_disable(struct task_struct 
  #ifdef TIF_SYSCALL_EMU
        clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
  #endif
 -      if (child->thread.ds_area_msr) {
 -#ifdef X86_BTS
 -              ptrace_bts_realloc(child, 0, 0);
 -#endif
 -              child->thread.debugctlmsr &= ~ds_debugctl_mask();
 -              if (!child->thread.debugctlmsr)
 -                      clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
 -              clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
 -      }
 +#ifdef CONFIG_X86_PTRACE_BTS
 +      (void)ds_release_bts(child);
 +
 +      child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask;
 +      if (!child->thread.debugctlmsr)
 +              clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR);
 +
 +      clear_tsk_thread_flag(child, TIF_BTS_TRACE_TS);
 +#endif /* CONFIG_X86_PTRACE_BTS */
  }
  
  #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
@@@ -1037,13 -943,13 +1037,13 @@@ long arch_ptrace(struct task_struct *ch
                return copy_regset_to_user(child, &user_x86_32_view,
                                           REGSET_XFP,
                                           0, sizeof(struct user_fxsr_struct),
-                                          datap);
+                                          datap) ? -EIO : 0;
  
        case PTRACE_SETFPXREGS: /* Set the child extended FPU state. */
                return copy_regset_from_user(child, &user_x86_32_view,
                                             REGSET_XFP,
                                             0, sizeof(struct user_fxsr_struct),
-                                            datap);
+                                            datap) ? -EIO : 0;
  #endif
  
  #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
        /*
         * These bits need more cooking - not enabled yet:
         */
 -#ifdef X86_BTS
 +#ifdef CONFIG_X86_PTRACE_BTS
        case PTRACE_BTS_CONFIG:
                ret = ptrace_bts_config
                        (child, data, (struct ptrace_bts_config __user *)addr);
                break;
  
        case PTRACE_BTS_SIZE:
 -              ret = ptrace_bts_get_size(child);
 +              ret = ds_get_bts_index(child, /* pos = */ 0);
                break;
  
        case PTRACE_BTS_GET:
                break;
  
        case PTRACE_BTS_CLEAR:
 -              ret = ptrace_bts_clear(child);
 +              ret = ds_clear_bts(child);
                break;
  
        case PTRACE_BTS_DRAIN:
                ret = ptrace_bts_drain
                        (child, data, (struct bts_struct __user *) addr);
                break;
 -#endif
 +#endif /* CONFIG_X86_PTRACE_BTS */
  
        default:
                ret = ptrace_request(child, request, addr, data);
@@@ -1451,8 -1357,6 +1451,6 @@@ const struct user_regset_view *task_use
  #endif
  }
  
- #ifdef CONFIG_X86_32
  void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
  {
        struct siginfo info;
        force_sig_info(SIGTRAP, &info, tsk);
  }
  
- /* notification of system call entry/exit
-  * - triggered by current->work.syscall_trace
-  */
- int do_syscall_trace(struct pt_regs *regs, int entryexit)
- {
-       int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU);
-       /*
-        * With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP for syscall
-        * interception
-        */
-       int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP);
-       int ret = 0;
-       /* do the secure computing check first */
-       if (!entryexit)
-               secure_computing(regs->orig_ax);
-       if (unlikely(current->audit_context)) {
-               if (entryexit)
-                       audit_syscall_exit(AUDITSC_RESULT(regs->ax),
-                                               regs->ax);
-               /* Debug traps, when using PTRACE_SINGLESTEP, must be sent only
-                * on the syscall exit path. Normally, when TIF_SYSCALL_AUDIT is
-                * not used, entry.S will call us only on syscall exit, not
-                * entry; so when TIF_SYSCALL_AUDIT is used we must avoid
-                * calling send_sigtrap() on syscall entry.
-                *
-                * Note that when PTRACE_SYSEMU_SINGLESTEP is used,
-                * is_singlestep is false, despite his name, so we will still do
-                * the correct thing.
-                */
-               else if (is_singlestep)
-                       goto out;
-       }
-       if (!(current->ptrace & PT_PTRACED))
-               goto out;
-       /* If a process stops on the 1st tracepoint with SYSCALL_TRACE
-        * and then is resumed with SYSEMU_SINGLESTEP, it will come in
-        * here. We have to check this and return */
-       if (is_sysemu && entryexit)
-               return 0;
-       /* Fake a debug trap */
-       if (is_singlestep)
-               send_sigtrap(current, regs, 0);
-       if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu)
-               goto out;
-       /* the 0x80 provides a way for the tracing parent to distinguish
-          between a syscall stop and SIGTRAP delivery */
-       /* Note that the debugger could change the result of test_thread_flag!*/
-       ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80:0));
-       /*
-        * this isn't the same as continuing with a signal, but it will do
-        * for normal use.  strace only continues with a signal if the
-        * stopping signal is not SIGTRAP.  -brl
-        */
-       if (current->exit_code) {
-               send_sig(current->exit_code, current, 1);
-               current->exit_code = 0;
-       }
-       ret = is_sysemu;
- out:
-       if (unlikely(current->audit_context) && !entryexit)
-               audit_syscall_entry(AUDIT_ARCH_I386, regs->orig_ax,
-                                   regs->bx, regs->cx, regs->dx, regs->si);
-       if (ret == 0)
-               return 0;
-       regs->orig_ax = -1; /* force skip of syscall restarting */
-       if (unlikely(current->audit_context))
-               audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
-       return 1;
- }
- #else  /* CONFIG_X86_64 */
  static void syscall_trace(struct pt_regs *regs)
  {
+       if (!(current->ptrace & PT_PTRACED))
+               return;
  
  #if 0
        printk("trace %s ip %lx sp %lx ax %d origrax %d caller %lx tiflags %x ptrace %x\n",
        }
  }
  
- asmlinkage void syscall_trace_enter(struct pt_regs *regs)
+ #ifdef CONFIG_X86_32
+ # define IS_IA32      1
+ #elif defined CONFIG_IA32_EMULATION
+ # define IS_IA32      test_thread_flag(TIF_IA32)
+ #else
+ # define IS_IA32      0
+ #endif
+ /*
+  * We must return the syscall number to actually look up in the table.
+  * This can be -1L to skip running any syscall at all.
+  */
+ asmregparm long syscall_trace_enter(struct pt_regs *regs)
  {
+       long ret = 0;
+       /*
+        * If we stepped into a sysenter/syscall insn, it trapped in
+        * kernel mode; do_debug() cleared TF and set TIF_SINGLESTEP.
+        * If user-mode had set TF itself, then it's still clear from
+        * do_debug() and we need to set it again to restore the user
+        * state.  If we entered on the slow path, TF was already set.
+        */
+       if (test_thread_flag(TIF_SINGLESTEP))
+               regs->flags |= X86_EFLAGS_TF;
        /* do the secure computing check first */
        secure_computing(regs->orig_ax);
  
-       if (test_thread_flag(TIF_SYSCALL_TRACE)
-           && (current->ptrace & PT_PTRACED))
+       if (unlikely(test_thread_flag(TIF_SYSCALL_EMU)))
+               ret = -1L;
+       if (ret || test_thread_flag(TIF_SYSCALL_TRACE))
                syscall_trace(regs);
  
        if (unlikely(current->audit_context)) {
-               if (test_thread_flag(TIF_IA32)) {
+               if (IS_IA32)
                        audit_syscall_entry(AUDIT_ARCH_I386,
                                            regs->orig_ax,
                                            regs->bx, regs->cx,
                                            regs->dx, regs->si);
-               } else {
+ #ifdef CONFIG_X86_64
+               else
                        audit_syscall_entry(AUDIT_ARCH_X86_64,
                                            regs->orig_ax,
                                            regs->di, regs->si,
                                            regs->dx, regs->r10);
-               }
+ #endif
        }
+       return ret ?: regs->orig_ax;
  }
  
- asmlinkage void syscall_trace_leave(struct pt_regs *regs)
+ asmregparm void syscall_trace_leave(struct pt_regs *regs)
  {
        if (unlikely(current->audit_context))
                audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
  
-       if ((test_thread_flag(TIF_SYSCALL_TRACE)
-            || test_thread_flag(TIF_SINGLESTEP))
-           && (current->ptrace & PT_PTRACED))
+       if (test_thread_flag(TIF_SYSCALL_TRACE))
                syscall_trace(regs);
- }
  
- #endif        /* CONFIG_X86_32 */
+       /*
+        * If TIF_SYSCALL_EMU is set, we only get here because of
+        * TIF_SINGLESTEP (i.e. this is PTRACE_SYSEMU_SINGLESTEP).
+        * We already reported this syscall instruction in
+        * syscall_trace_enter(), so don't do any more now.
+        */
+       if (unlikely(test_thread_flag(TIF_SYSCALL_EMU)))
+               return;
+       /*
+        * If we are single-stepping, synthesize a trap to follow the
+        * system call instruction.
+        */
+       if (test_thread_flag(TIF_SINGLESTEP) &&
+           (current->ptrace & PT_PTRACED))
+               send_sigtrap(current, regs, 0);
+ }
index beaccb71628f75bbb09dbf3f8662acf46231cd74,5f58da401b43696ee861377fb9aba53500af8b8e..ec09649c01f356f7c37a27857b99a3dba7588bd4
@@@ -20,7 -20,6 +20,7 @@@ struct mm_struct
  #include <asm/msr.h>
  #include <asm/desc_defs.h>
  #include <asm/nops.h>
 +#include <asm/ds.h>
  
  #include <linux/personality.h>
  #include <linux/cpumask.h>
@@@ -135,7 -134,7 +135,7 @@@ extern __u32                       cleared_cpu_caps[NCAPINT
  #ifdef CONFIG_SMP
  DECLARE_PER_CPU(struct cpuinfo_x86, cpu_info);
  #define cpu_data(cpu)         per_cpu(cpu_info, cpu)
- #define current_cpu_data      cpu_data(smp_processor_id())
+ #define current_cpu_data      __get_cpu_var(cpu_info)
  #else
  #define cpu_data(cpu)         boot_cpu_data
  #define current_cpu_data      boot_cpu_data
@@@ -154,7 -153,7 +154,7 @@@ static inline int hlt_works(int cpu
  
  extern void cpu_detect(struct cpuinfo_x86 *c);
  
- extern void identify_cpu(struct cpuinfo_x86 *);
+ extern void early_cpu_init(void);
  extern void identify_boot_cpu(void);
  extern void identify_secondary_cpu(struct cpuinfo_x86 *);
  extern void print_cpu_info(struct cpuinfo_x86 *);
@@@ -263,16 -262,12 +263,12 @@@ struct tss_struct 
        unsigned long           io_bitmap_max;
        struct thread_struct    *io_bitmap_owner;
  
-       /*
-        * Pad the TSS to be cacheline-aligned (size is 0x100):
-        */
-       unsigned long           __cacheline_filler[35];
        /*
         * .. and then another 0x100 bytes for the emergency kernel stack:
         */
        unsigned long           stack[64];
  
- } __attribute__((packed));
+ } ____cacheline_aligned;
  
  DECLARE_PER_CPU(struct tss_struct, init_tss);
  
@@@ -416,14 -411,9 +412,14 @@@ struct thread_struct 
        unsigned                io_bitmap_max;
  /* MSR_IA32_DEBUGCTLMSR value to switch in if TIF_DEBUGCTLMSR is set.  */
        unsigned long   debugctlmsr;
 -/* Debug Store - if not 0 points to a DS Save Area configuration;
 - *               goes into MSR_IA32_DS_AREA */
 -      unsigned long   ds_area_msr;
 +#ifdef CONFIG_X86_DS
 +/* Debug Store context; see include/asm-x86/ds.h; goes into MSR_IA32_DS_AREA */
 +      struct ds_context       *ds_ctx;
 +#endif /* CONFIG_X86_DS */
 +#ifdef CONFIG_X86_PTRACE_BTS
 +/* the signal to send on a bts buffer overflow */
 +      unsigned int    bts_ovfl_signal;
 +#endif /* CONFIG_X86_PTRACE_BTS */
  };
  
  static inline unsigned long native_get_debugreg(int regno)
@@@ -541,7 -531,6 +537,6 @@@ static inline void load_sp0(struct tss_
  }
  
  #define set_iopl_mask native_set_iopl_mask
- #define SWAPGS        swapgs
  #endif /* CONFIG_PARAVIRT */
  
  /*
@@@ -733,11 -722,11 +728,11 @@@ static inline void __sti_mwait(unsigne
  
  extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx);
  
- extern int                    force_mwait;
  extern void select_idle_routine(const struct cpuinfo_x86 *c);
  
  extern unsigned long          boot_option_idle_override;
+ extern unsigned long          idle_halt;
+ extern unsigned long          idle_nomwait;
  
  extern void enable_sep_cpu(void);
  extern int sysenter_setup(void);
index 9bcaa75cbcafa61e1e520b906051785e0f2cc1b6,72e7b9db29bba0e2cb736d86281ab4f7c24cdd1d..3397817eded997c054286ea00a2081f9051f26ba
  
  #ifdef __x86_64__
  # define PTRACE_ARCH_PRCTL      30
- #else
- # define PTRACE_SYSEMU                  31
- # define PTRACE_SYSEMU_SINGLESTEP 32
  #endif
  
+ #define PTRACE_SYSEMU           31
+ #define PTRACE_SYSEMU_SINGLESTEP  32
  #define PTRACE_SINGLEBLOCK    33      /* resume execution until next branch */
  
 -#ifndef __ASSEMBLY__
 +#ifdef CONFIG_X86_PTRACE_BTS
  
 +#ifndef __ASSEMBLY__
  #include <asm/types.h>
  
  /* configuration/status structure used in PTRACE_BTS_CONFIG and
@@@ -98,20 -97,20 +98,20 @@@ struct ptrace_bts_config 
        /* actual size of bts_struct in bytes */
        __u32 bts_size;
  };
 -#endif
 +#endif /* __ASSEMBLY__ */
  
  #define PTRACE_BTS_O_TRACE    0x1 /* branch trace */
  #define PTRACE_BTS_O_SCHED    0x2 /* scheduling events w/ jiffies */
  #define PTRACE_BTS_O_SIGNAL     0x4 /* send SIG<signal> on buffer overflow
                                       instead of wrapping around */
 -#define PTRACE_BTS_O_CUT_SIZE 0x8 /* cut requested size to max available
 -                                     instead of failing */
 +#define PTRACE_BTS_O_ALLOC    0x8 /* (re)allocate buffer */
  
  #define PTRACE_BTS_CONFIG     40
  /* Configure branch trace recording.
     ADDR points to a struct ptrace_bts_config.
     DATA gives the size of that buffer.
 -   A new buffer is allocated, iff the size changes.
 +   A new buffer is allocated, if requested in the flags.
 +   An overflow signal may only be requested for new buffers.
     Returns the number of bytes read.
  */
  #define PTRACE_BTS_STATUS     41
     Returns the number of bytes written.
  */
  #define PTRACE_BTS_SIZE               42
 -/* Return the number of available BTS records.
 +/* Return the number of available BTS records for draining.
     DATA and ADDR are ignored.
  */
  #define PTRACE_BTS_GET                43
     BTS records are read from oldest to newest.
     Returns number of BTS records drained.
  */
 +#endif /* CONFIG_X86_PTRACE_BTS */
  
  #endif
diff --combined include/asm-x86/ptrace.h
index 6303701d18e3bc598fefb0f27326fd99d00f3ec8,8a71db803da6666bf030223503e0dcebf2778efd..5e0c48d24b1a61642806de0b5eaaf37a9e50aacd
@@@ -3,7 -3,12 +3,12 @@@
  
  #include <linux/compiler.h>   /* For __user */
  #include <asm/ptrace-abi.h>
+ #include <asm/processor-flags.h>
  
+ #ifdef __KERNEL__
+ #include <asm/ds.h>           /* the DS BTS struct is used for ptrace too */
+ #include <asm/segment.h>
+ #endif
  
  #ifndef __ASSEMBLY__
  
@@@ -55,9 -60,6 +60,6 @@@ struct pt_regs 
        unsigned long ss;
  };
  
- #include <asm/vm86.h>
- #include <asm/segment.h>
  #endif /* __KERNEL__ */
  
  #else /* __i386__ */
@@@ -125,48 -127,14 +127,48 @@@ struct pt_regs 
  #endif /* __KERNEL__ */
  #endif /* !__i386__ */
  
 +
 +#ifdef CONFIG_X86_PTRACE_BTS
 +/* a branch trace record entry
 + *
 + * In order to unify the interface between various processor versions,
 + * we use the below data structure for all processors.
 + */
 +enum bts_qualifier {
 +      BTS_INVALID = 0,
 +      BTS_BRANCH,
 +      BTS_TASK_ARRIVES,
 +      BTS_TASK_DEPARTS
 +};
 +
 +struct bts_struct {
 +      __u64 qualifier;
 +      union {
 +              /* BTS_BRANCH */
 +              struct {
 +                      __u64 from_ip;
 +                      __u64 to_ip;
 +              } lbr;
 +              /* BTS_TASK_ARRIVES or
 +                 BTS_TASK_DEPARTS */
 +              __u64 jiffies;
 +      } variant;
 +};
 +#endif /* CONFIG_X86_PTRACE_BTS */
 +
  #ifdef __KERNEL__
  
 -/* the DS BTS struct is used for ptrace as well */
 -#include <asm/ds.h>
 +#include <linux/init.h>
  
 +struct cpuinfo_x86;
  struct task_struct;
  
 +#ifdef CONFIG_X86_PTRACE_BTS
 +extern void __cpuinit ptrace_bts_init_intel(struct cpuinfo_x86 *);
  extern void ptrace_bts_take_timestamp(struct task_struct *, enum bts_qualifier);
 +#else
 +#define ptrace_bts_init_intel(config) do {} while (0)
 +#endif /* CONFIG_X86_PTRACE_BTS */
  
  extern unsigned long profile_pc(struct pt_regs *regs);