[PATCH] x86: GDT alignment fix
authorZachary Amsden <zach@vmware.com>
Fri, 6 Jan 2006 08:11:47 +0000 (00:11 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Fri, 6 Jan 2006 16:33:33 +0000 (08:33 -0800)
Make GDT page aligned and page padded to support running inside of a
hypervisor.  This prevents false sharing of the GDT page with other hot
data, which is not allowed in Xen, and causes performance problems in
VMware.

Rather than go back to the old method of statically allocating the GDT
(which wastes unneded space for non-present CPUs), the GDT for APs is
allocated dynamically.

Signed-off-by: Zachary Amsden <zach@vmware.com>
Cc: "Seth, Rohit" <rohit.seth@intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/i386/kernel/apm.c
arch/i386/kernel/cpu/common.c
arch/i386/kernel/head.S
arch/i386/kernel/i386_ksyms.c
arch/i386/kernel/smpboot.c
drivers/pnp/pnpbios/bioscalls.c
include/asm-i386/desc.h

index 1e60acbed3c1468189d6323437a03420383deb25..6c8e483ce9e40af033e3cbc063db9442c90b3a75 100644 (file)
@@ -2317,6 +2317,8 @@ static int __init apm_init(void)
 
        for (i = 0; i < NR_CPUS; i++) {
                struct desc_struct *gdt = get_cpu_gdt_table(i);
+               if (!gdt)
+                       continue;
                set_base(gdt[APM_CS >> 3],
                         __va((unsigned long)apm_info.bios.cseg << 4));
                set_base(gdt[APM_CS_16 >> 3],
index 31e344b26bae824f255baa1446980486d8aff52a..cbc32069683f9bc3a2e516e37da88285e833385e 100644 (file)
@@ -18,9 +18,6 @@
 
 #include "cpu.h"
 
-DEFINE_PER_CPU(struct desc_struct, cpu_gdt_table[GDT_ENTRIES]);
-EXPORT_PER_CPU_SYMBOL(cpu_gdt_table);
-
 DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]);
 EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack);
 
index e437fb367498c029ea21f5a7d5495d6b965a70cd..870f20bf33c83325988b28b7343e6464aada4388 100644 (file)
@@ -525,3 +525,5 @@ ENTRY(cpu_gdt_table)
        .quad 0x0000000000000000        /* 0xf0 - unused */
        .quad 0x0000000000000000        /* 0xf8 - GDT entry 31: double-fault TSS */
 
+       /* Be sure this is zeroed to avoid false validations in Xen */
+       .fill PAGE_SIZE_asm / 8 - GDT_ENTRIES,8,0
index 180f070d03cbe205f50ebaf0828c26755e3320b9..3999bec50c33d4aceb332d355a0bba15ddfaf3de 100644 (file)
@@ -3,8 +3,7 @@
 #include <asm/checksum.h>
 #include <asm/desc.h>
 
-/* This is definitely a GPL-only symbol */
-EXPORT_SYMBOL_GPL(cpu_gdt_table);
+EXPORT_SYMBOL_GPL(cpu_gdt_descr);
 
 EXPORT_SYMBOL(__down_failed);
 EXPORT_SYMBOL(__down_failed_interruptible);
index 9ed449af8e9fdd350a42ff2c606c0af154dad875..b3c2e2c26743381e5f1a8b3dfd592c2c0cb5d2c9 100644 (file)
@@ -903,6 +903,12 @@ static int __devinit do_boot_cpu(int apicid, int cpu)
        unsigned long start_eip;
        unsigned short nmi_high = 0, nmi_low = 0;
 
+       if (!cpu_gdt_descr[cpu].address &&
+           !(cpu_gdt_descr[cpu].address = get_zeroed_page(GFP_KERNEL))) {
+               printk("Failed to allocate GDT for CPU %d\n", cpu);
+               return 1;
+       }
+
        ++cpucount;
 
        /*
index 6b7583f497d0a36f2862806c65e23c80f5ee52c6..7cb476ed7f9183a0ef54fe2fec241b4fab93960b 100644 (file)
@@ -69,14 +69,16 @@ __asm__(
 
 #define Q_SET_SEL(cpu, selname, address, size) \
 do { \
-set_base(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], __va((u32)(address))); \
-set_limit(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], size); \
+struct desc_struct *gdt = get_cpu_gdt_table((cpu)); \
+set_base(gdt[(selname) >> 3], __va((u32)(address))); \
+set_limit(gdt[(selname) >> 3], size); \
 } while(0)
 
 #define Q2_SET_SEL(cpu, selname, address, size) \
 do { \
-set_base(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], (u32)(address)); \
-set_limit(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], size); \
+struct desc_struct *gdt = get_cpu_gdt_table((cpu)); \
+set_base(gdt[(selname) >> 3], (u32)(address)); \
+set_limit(gdt[(selname) >> 3], size); \
 } while(0)
 
 static struct desc_struct bad_bios_desc = { 0, 0x00409200 };
@@ -115,8 +117,8 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
                return PNP_FUNCTION_NOT_SUPPORTED;
 
        cpu = get_cpu();
-       save_desc_40 = per_cpu(cpu_gdt_table,cpu)[0x40 / 8];
-       per_cpu(cpu_gdt_table,cpu)[0x40 / 8] = bad_bios_desc;
+       save_desc_40 = get_cpu_gdt_table(cpu)[0x40 / 8];
+       get_cpu_gdt_table(cpu)[0x40 / 8] = bad_bios_desc;
 
        /* On some boxes IRQ's during PnP BIOS calls are deadly.  */
        spin_lock_irqsave(&pnp_bios_lock, flags);
@@ -158,7 +160,7 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
        );
        spin_unlock_irqrestore(&pnp_bios_lock, flags);
 
-       per_cpu(cpu_gdt_table,cpu)[0x40 / 8] = save_desc_40;
+       get_cpu_gdt_table(cpu)[0x40 / 8] = save_desc_40;
        put_cpu();
 
        /* If we get here and this is set then the PnP BIOS faulted on us. */
@@ -535,8 +537,10 @@ void pnpbios_calls_init(union pnp_bios_install_struct *header)
 
        set_base(bad_bios_desc, __va((unsigned long)0x40 << 4));
        _set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4));
-       for(i=0; i < NR_CPUS; i++)
-       {
+       for (i = 0; i < NR_CPUS; i++) {
+               struct desc_struct *gdt = get_cpu_gdt_table(i);
+               if (!gdt)
+                       continue;
                Q2_SET_SEL(i, PNP_CS32, &pnp_bios_callfunc, 64 * 1024);
                Q_SET_SEL(i, PNP_CS16, header->fields.pm16cseg, 64 * 1024);
                Q_SET_SEL(i, PNP_DS, header->fields.pm16dseg, 64 * 1024);
index 29b851a18c6ed6f0ba119f0ad5d727e3ae3a8c9f..494e73bca0956c2f327e0eaf07e1cb83752cf3bb 100644 (file)
@@ -15,9 +15,6 @@
 #include <asm/mmu.h>
 
 extern struct desc_struct cpu_gdt_table[GDT_ENTRIES];
-DECLARE_PER_CPU(struct desc_struct, cpu_gdt_table[GDT_ENTRIES]);
-
-#define get_cpu_gdt_table(_cpu) (per_cpu(cpu_gdt_table,_cpu))
 
 DECLARE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]);
 
@@ -29,6 +26,11 @@ struct Xgt_desc_struct {
 
 extern struct Xgt_desc_struct idt_descr, cpu_gdt_descr[NR_CPUS];
 
+static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu)
+{
+       return ((struct desc_struct *)cpu_gdt_descr[cpu].address);
+}
+
 #define load_TR_desc() __asm__ __volatile__("ltr %w0"::"q" (GDT_ENTRY_TSS*8))
 #define load_LDT_desc() __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8))