[PATCH] x86: fix PDA variables to work during boot

The current PDA code, which went in in post 2.6.19 has a flaw in that it
doesn't correctly cycle the GDT and %GS segment through the boot PDA,
the CPU PDA and finally the per-cpu PDA.

The bug generally doesn't show up if the boot CPU id is zero, but
everything falls apart for a non zero boot CPU id. The basically kills
voyager which is perfectly capable of doing non zero CPU id boots, so
voyager currently won't boot without this.

The fix is to be careful and actually do the GDT setups correctly.

Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Cc: Andi Kleen <ak@suse.de>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by James Bottomley and committed by Linus Torvalds 9ee79a3d ebcccd14

+22 -7
+9 -4
arch/i386/kernel/cpu/common.c
··· 710 return 1; 711 } 712 713 - /* Common CPU init for both boot and secondary CPUs */ 714 - static void __cpuinit _cpu_init(int cpu, struct task_struct *curr) 715 { 716 - struct tss_struct * t = &per_cpu(init_tss, cpu); 717 - struct thread_struct *thread = &curr->thread; 718 struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); 719 720 /* Reinit these anyway, even if they've already been done (on ··· 719 the real ones). */ 720 load_gdt(cpu_gdt_descr); 721 set_kernel_gs(); 722 723 if (cpu_test_and_set(cpu, cpu_initialized)) { 724 printk(KERN_WARNING "CPU#%d already initialized!\n", cpu); ··· 811 local_irq_enable(); 812 } 813 814 _cpu_init(cpu, curr); 815 } 816
··· 710 return 1; 711 } 712 713 + void __cpuinit cpu_set_gdt(int cpu) 714 { 715 struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); 716 717 /* Reinit these anyway, even if they've already been done (on ··· 722 the real ones). */ 723 load_gdt(cpu_gdt_descr); 724 set_kernel_gs(); 725 + } 726 + 727 + /* Common CPU init for both boot and secondary CPUs */ 728 + static void __cpuinit _cpu_init(int cpu, struct task_struct *curr) 729 + { 730 + struct tss_struct * t = &per_cpu(init_tss, cpu); 731 + struct thread_struct *thread = &curr->thread; 732 733 if (cpu_test_and_set(cpu, cpu_initialized)) { 734 printk(KERN_WARNING "CPU#%d already initialized!\n", cpu); ··· 807 local_irq_enable(); 808 } 809 810 + cpu_set_gdt(cpu); 811 _cpu_init(cpu, curr); 812 } 813
+6 -3
arch/i386/kernel/smpboot.c
··· 596 void __devinit initialize_secondary(void) 597 { 598 /* 599 * We don't actually need to load the full TSS, 600 * basically just the stack pointer and the eip. 601 */ ··· 977 printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip); 978 /* Stack for startup_32 can be just as for start_secondary onwards */ 979 stack_start.esp = (void *) idle->thread.esp; 980 - 981 - start_pda = cpu_pda(cpu); 982 - cpu_gdt_descr = per_cpu(cpu_gdt_descr, cpu); 983 984 irq_ctx_init(cpu); 985
··· 596 void __devinit initialize_secondary(void) 597 { 598 /* 599 + * switch to the per CPU GDT we already set up 600 + * in do_boot_cpu() 601 + */ 602 + cpu_set_gdt(current_thread_info()->cpu); 603 + 604 + /* 605 * We don't actually need to load the full TSS, 606 * basically just the stack pointer and the eip. 607 */ ··· 971 printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip); 972 /* Stack for startup_32 can be just as for start_secondary onwards */ 973 stack_start.esp = (void *) idle->thread.esp; 974 975 irq_ctx_init(cpu); 976
+6
arch/i386/mach-voyager/voyager_smp.c
··· 773 #endif 774 775 /* 776 * We don't actually need to load the full TSS, 777 * basically just the stack pointer and the eip. 778 */
··· 773 #endif 774 775 /* 776 + * switch to the per CPU GDT we already set up 777 + * in do_boot_cpu() 778 + */ 779 + cpu_set_gdt(current_thread_info()->cpu); 780 + 781 + /* 782 * We don't actually need to load the full TSS, 783 * basically just the stack pointer and the eip. 784 */
+1
include/asm-i386/processor.h
··· 743 extern int sysenter_setup(void); 744 745 extern int init_gdt(int cpu, struct task_struct *idle); 746 extern void secondary_cpu_init(void); 747 748 #endif /* __ASM_I386_PROCESSOR_H */
··· 743 extern int sysenter_setup(void); 744 745 extern int init_gdt(int cpu, struct task_struct *idle); 746 + extern void cpu_set_gdt(int); 747 extern void secondary_cpu_init(void); 748 749 #endif /* __ASM_I386_PROCESSOR_H */