[PATCH] x86_64: Align and pad x86_64 GDT on page boundary
authorRavikiran G Thirumalai <kiran@scalex86.org>
Wed, 11 Jan 2006 21:43:57 +0000 (22:43 +0100)
committerLinus Torvalds <torvalds@g5.osdl.org>
Thu, 12 Jan 2006 03:04:53 +0000 (19:04 -0800)
This patch is on the same lines as Zachary Amsden's i386 GDT page alignemnt
patch in -mm, but for x86_64.

Patch to align and pad x86_64 GDT on page boundries.

[AK: some minor cleanups and fixed incorrect TLS initialization
in CPU init.]

Signed-off-by: Nippun Goel <nippung@calsoftinc.com>
Signed-off-by: Ravikiran Thirumalai <kiran@scalex86.org>
Signed-off-by: Shai Fultheim <shai@scalex86.org>
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/x86_64/kernel/head.S
arch/x86_64/kernel/setup64.c
arch/x86_64/kernel/smpboot.c
arch/x86_64/kernel/suspend.c
include/asm-x86_64/desc.h

index 15290968e49db562753b720f15b9d564500f5668..1d216a9fc6d840502bbb07da9ff8ab5d81f09a68 100644 (file)
@@ -379,7 +379,7 @@ gdt:
  * Also sysret mandates a special GDT layout 
  */
                                
-.align L1_CACHE_BYTES
+.align PAGE_SIZE
 
 /* The TLS descriptors are currently at a different place compared to i386.
    Hopefully nobody expects them at a fixed place (Wine?) */
@@ -401,10 +401,11 @@ ENTRY(cpu_gdt_table)
 gdt_end:       
        /* asm/segment.h:GDT_ENTRIES must match this */ 
        /* This should be a multiple of the cache line size */
-       /* GDTs of other CPUs: */       
-       .fill (GDT_SIZE * NR_CPUS) - (gdt_end - cpu_gdt_table)
+       /* GDTs of other CPUs are now dynamically allocated */
+
+       /* zero the remaining page */
+       .fill PAGE_SIZE / 8 - GDT_ENTRIES,8,0
 
-       .align  L1_CACHE_BYTES
 ENTRY(idt_table)       
        .rept   256
        .quad   0
index 39e728cfe6a07ecba8947f2382e3b9f1e5919155..972f5d4ce823fd413742891c137d0ab25d042c21 100644 (file)
@@ -213,16 +213,14 @@ void __cpuinit cpu_init (void)
         * Initialize the per-CPU GDT with the boot GDT,
         * and set up the GDT descriptor:
         */
-       if (cpu) {
-               memcpy(cpu_gdt_table[cpu], cpu_gdt_table[0], GDT_SIZE);
-       }       
+       if (cpu)
+               memcpy(cpu_gdt(cpu), cpu_gdt_table, GDT_SIZE);
 
        cpu_gdt_descr[cpu].size = GDT_SIZE;
-       cpu_gdt_descr[cpu].address = (unsigned long)cpu_gdt_table[cpu];
        asm volatile("lgdt %0" :: "m" (cpu_gdt_descr[cpu]));
        asm volatile("lidt %0" :: "m" (idt_descr));
 
-       memcpy(me->thread.tls_array, cpu_gdt_table[cpu], GDT_ENTRY_TLS_ENTRIES * 8);
+       memset(me->thread.tls_array, 0, GDT_ENTRY_TLS_ENTRIES * 8);
        syscall_init();
 
        wrmsrl(MSR_FS_BASE, 0);
index f513dacc177f82224745344b1bd335bc27dc5a18..e6af93b51dce39cebdd9a4fc03798f8442a2d15c 100644 (file)
@@ -744,6 +744,13 @@ static int __cpuinit do_boot_cpu(int cpu, int apicid)
        };
        DECLARE_WORK(work, do_fork_idle, &c_idle);
 
+       /* allocate memory for gdts of secondary cpus. Hotplug is considered */
+       if (!cpu_gdt_descr[cpu].address &&
+               !(cpu_gdt_descr[cpu].address = get_zeroed_page(GFP_KERNEL))) {
+               printk(KERN_ERR "Failed to allocate GDT for CPU %d\n", cpu);
+               return -1;
+       }
+
        c_idle.idle = get_idle_for_cpu(cpu);
 
        if (c_idle.idle) {
index fd2bef7808825fe670b3a6864cd9b7208f6746a4..ecbd34c1093d0a03109a9c99fe7c9c1c61cf646a 100644 (file)
@@ -120,7 +120,7 @@ void fix_processor_context(void)
 
        set_tss_desc(cpu,t);    /* This just modifies memory; should not be neccessary. But... This is neccessary, because 386 hardware has concept of busy TSS or some similar stupidity. */
 
-       cpu_gdt_table[cpu][GDT_ENTRY_TSS].type = 9;
+       cpu_gdt(cpu)[GDT_ENTRY_TSS].type = 9;
 
        syscall_init();                         /* This sets MSR_*STAR and related */
        load_TR_desc();                         /* This does ltr */
index 5ce0e34f9a0cb3b4e38759b927b7b86080a46106..eb7723a467908b5f86cb0e2fc2dd24168c8e523d 100644 (file)
@@ -25,7 +25,7 @@ struct n_desc_struct {
        unsigned int a,b;
 };     
 
-extern struct desc_struct cpu_gdt_table[NR_CPUS][GDT_ENTRIES];
+extern struct desc_struct cpu_gdt_table[GDT_ENTRIES];
 
 enum { 
        GATE_INTERRUPT = 0xE, 
@@ -79,6 +79,9 @@ extern struct desc_struct default_ldt[];
 extern struct gate_struct idt_table[]; 
 extern struct desc_ptr cpu_gdt_descr[];
 
+/* the cpu gdt accessor */
+#define cpu_gdt(_cpu) ((struct desc_struct *)cpu_gdt_descr[_cpu].address)
+
 static inline void _set_gate(void *adr, unsigned type, unsigned long func, unsigned dpl, unsigned ist)  
 {
        struct gate_struct s;   
@@ -144,20 +147,20 @@ static inline void set_tss_desc(unsigned cpu, void *addr)
         * -1? seg base+limit should be pointing to the address of the
         * last valid byte
         */
-       set_tssldt_descriptor(&cpu_gdt_table[cpu][GDT_ENTRY_TSS],
+       set_tssldt_descriptor(&cpu_gdt(cpu)[GDT_ENTRY_TSS],
                (unsigned long)addr, DESC_TSS,
                IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1);
 } 
 
 static inline void set_ldt_desc(unsigned cpu, void *addr, int size)
 { 
-       set_tssldt_descriptor(&cpu_gdt_table[cpu][GDT_ENTRY_LDT], (unsigned long)addr, 
+       set_tssldt_descriptor(&cpu_gdt(cpu)[GDT_ENTRY_LDT], (unsigned long)addr,
                              DESC_LDT, size * 8 - 1);
 }
 
 static inline void set_seg_base(unsigned cpu, int entry, void *base)
 { 
-       struct desc_struct *d = &cpu_gdt_table[cpu][entry];
+       struct desc_struct *d = &cpu_gdt(cpu)[entry];
        u32 addr = (u32)(u64)base;
        BUG_ON((u64)base >> 32); 
        d->base0 = addr & 0xffff;
@@ -199,7 +202,7 @@ static inline void set_seg_base(unsigned cpu, int entry, void *base)
 
 static inline void load_TLS(struct thread_struct *t, unsigned int cpu)
 {
-       u64 *gdt = (u64 *)(cpu_gdt_table[cpu] + GDT_ENTRY_TLS_MIN);
+       u64 *gdt = (u64 *)(cpu_gdt(cpu) + GDT_ENTRY_TLS_MIN);
        gdt[0] = t->tls_array[0];
        gdt[1] = t->tls_array[1];
        gdt[2] = t->tls_array[2];