diff options
author | Glauber Costa <gcosta@redhat.com> | 2008-05-28 19:19:53 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-07-08 06:48:16 -0400 |
commit | a939098afcfa5f81d3474782ec15c6d114e57763 (patch) | |
tree | 62c21fb10d6b58dc8247c34e68ab5562e045b8d0 | |
parent | 736f12bff9d9e7b4e895c64f73b190c8383fc2a1 (diff) |
x86: move x86_64 gdt closer to i386
i386 and x86_64 used two different schemes for maintaining the gdt.
With this patch, x86_64 initial gdt table is defined in a .c file,
same way as i386 is now. Also, we call it "gdt_page", and the descriptor,
"early_gdt_descr". This way we achieve common naming, which can allow for
more code integration.
Signed-off-by: Glauber Costa <gcosta@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/kernel/head_64.S | 48 | ||||
-rw-r--r-- | arch/x86/kernel/setup64.c | 5 | ||||
-rw-r--r-- | arch/x86/kernel/setup_64.c | 19 | ||||
-rw-r--r-- | arch/x86/kernel/smpboot.c | 12 | ||||
-rw-r--r-- | arch/x86/kernel/x8664_ksyms_64.c | 5 | ||||
-rw-r--r-- | include/asm-x86/desc.h | 24 | ||||
-rw-r--r-- | include/asm-x86/segment.h | 23 |
7 files changed, 48 insertions, 88 deletions
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 918a2711aff6..32f5a114d1a2 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S | |||
@@ -203,7 +203,7 @@ ENTRY(secondary_startup_64) | |||
203 | * addresses where we're currently running on. We have to do that here | 203 | * addresses where we're currently running on. We have to do that here |
204 | * because in 32bit we couldn't load a 64bit linear address. | 204 | * because in 32bit we couldn't load a 64bit linear address. |
205 | */ | 205 | */ |
206 | lgdt cpu_gdt_descr(%rip) | 206 | lgdt early_gdt_descr(%rip) |
207 | 207 | ||
208 | /* set up data segments. actually 0 would do too */ | 208 | /* set up data segments. actually 0 would do too */ |
209 | movl $__KERNEL_DS,%eax | 209 | movl $__KERNEL_DS,%eax |
@@ -391,54 +391,16 @@ NEXT_PAGE(level2_spare_pgt) | |||
391 | 391 | ||
392 | .data | 392 | .data |
393 | .align 16 | 393 | .align 16 |
394 | .globl cpu_gdt_descr | 394 | .globl early_gdt_descr |
395 | cpu_gdt_descr: | 395 | early_gdt_descr: |
396 | .word gdt_end-cpu_gdt_table-1 | 396 | .word GDT_ENTRIES*8-1 |
397 | gdt: | 397 | .quad per_cpu__gdt_page |
398 | .quad cpu_gdt_table | ||
399 | #ifdef CONFIG_SMP | ||
400 | .rept NR_CPUS-1 | ||
401 | .word 0 | ||
402 | .quad 0 | ||
403 | .endr | ||
404 | #endif | ||
405 | 398 | ||
406 | ENTRY(phys_base) | 399 | ENTRY(phys_base) |
407 | /* This must match the first entry in level2_kernel_pgt */ | 400 | /* This must match the first entry in level2_kernel_pgt */ |
408 | .quad 0x0000000000000000 | 401 | .quad 0x0000000000000000 |
409 | 402 | ||
410 | /* We need valid kernel segments for data and code in long mode too | ||
411 | * IRET will check the segment types kkeil 2000/10/28 | ||
412 | * Also sysret mandates a special GDT layout | ||
413 | */ | ||
414 | |||
415 | .section .data.page_aligned, "aw" | ||
416 | .align PAGE_SIZE | ||
417 | |||
418 | /* The TLS descriptors are currently at a different place compared to i386. | ||
419 | Hopefully nobody expects them at a fixed place (Wine?) */ | ||
420 | 403 | ||
421 | ENTRY(cpu_gdt_table) | ||
422 | .quad 0x0000000000000000 /* NULL descriptor */ | ||
423 | .quad 0x00cf9b000000ffff /* __KERNEL32_CS */ | ||
424 | .quad 0x00af9b000000ffff /* __KERNEL_CS */ | ||
425 | .quad 0x00cf93000000ffff /* __KERNEL_DS */ | ||
426 | .quad 0x00cffb000000ffff /* __USER32_CS */ | ||
427 | .quad 0x00cff3000000ffff /* __USER_DS, __USER32_DS */ | ||
428 | .quad 0x00affb000000ffff /* __USER_CS */ | ||
429 | .quad 0x0 /* unused */ | ||
430 | .quad 0,0 /* TSS */ | ||
431 | .quad 0,0 /* LDT */ | ||
432 | .quad 0,0,0 /* three TLS descriptors */ | ||
433 | .quad 0x0000f40000000000 /* node/CPU stored in limit */ | ||
434 | gdt_end: | ||
435 | /* asm/segment.h:GDT_ENTRIES must match this */ | ||
436 | /* This should be a multiple of the cache line size */ | ||
437 | /* GDTs of other CPUs are now dynamically allocated */ | ||
438 | |||
439 | /* zero the remaining page */ | ||
440 | .fill PAGE_SIZE / 8 - GDT_ENTRIES,8,0 | ||
441 | |||
442 | .section .bss, "aw", @nobits | 404 | .section .bss, "aw", @nobits |
443 | .align L1_CACHE_BYTES | 405 | .align L1_CACHE_BYTES |
444 | ENTRY(idt_table) | 406 | ENTRY(idt_table) |
diff --git a/arch/x86/kernel/setup64.c b/arch/x86/kernel/setup64.c index fc1a56da8240..70ff07186772 100644 --- a/arch/x86/kernel/setup64.c +++ b/arch/x86/kernel/setup64.c | |||
@@ -202,11 +202,8 @@ void __cpuinit cpu_init (void) | |||
202 | * Initialize the per-CPU GDT with the boot GDT, | 202 | * Initialize the per-CPU GDT with the boot GDT, |
203 | * and set up the GDT descriptor: | 203 | * and set up the GDT descriptor: |
204 | */ | 204 | */ |
205 | if (cpu) | ||
206 | memcpy(get_cpu_gdt_table(cpu), cpu_gdt_table, GDT_SIZE); | ||
207 | 205 | ||
208 | cpu_gdt_descr[cpu].size = GDT_SIZE; | 206 | switch_to_new_gdt(); |
209 | load_gdt((const struct desc_ptr *)&cpu_gdt_descr[cpu]); | ||
210 | load_idt((const struct desc_ptr *)&idt_descr); | 207 | load_idt((const struct desc_ptr *)&idt_descr); |
211 | 208 | ||
212 | memset(me->thread.tls_array, 0, GDT_ENTRY_TLS_ENTRIES * 8); | 209 | memset(me->thread.tls_array, 0, GDT_ENTRY_TLS_ENTRIES * 8); |
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c index 504caeaffd58..a93300de4da9 100644 --- a/arch/x86/kernel/setup_64.c +++ b/arch/x86/kernel/setup_64.c | |||
@@ -81,8 +81,6 @@ | |||
81 | #define ARCH_SETUP | 81 | #define ARCH_SETUP |
82 | #endif | 82 | #endif |
83 | 83 | ||
84 | #include "cpu/cpu.h" | ||
85 | |||
86 | /* | 84 | /* |
87 | * Machine setup.. | 85 | * Machine setup.. |
88 | */ | 86 | */ |
@@ -228,6 +226,23 @@ static inline void copy_edd(void) | |||
228 | } | 226 | } |
229 | #endif | 227 | #endif |
230 | 228 | ||
229 | /* Overridden in paravirt.c if CONFIG_PARAVIRT */ | ||
230 | void __attribute__((weak)) __init memory_setup(void) | ||
231 | { | ||
232 | machine_specific_memory_setup(); | ||
233 | } | ||
234 | |||
235 | /* Current gdt points %fs at the "master" per-cpu area: after this, | ||
236 | * it's on the real one. */ | ||
237 | void switch_to_new_gdt(void) | ||
238 | { | ||
239 | struct desc_ptr gdt_descr; | ||
240 | |||
241 | gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id()); | ||
242 | gdt_descr.size = GDT_SIZE - 1; | ||
243 | load_gdt(&gdt_descr); | ||
244 | } | ||
245 | |||
231 | /* | 246 | /* |
232 | * setup_arch - architecture-specific boot-time initializations | 247 | * setup_arch - architecture-specific boot-time initializations |
233 | * | 248 | * |
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index a71e3cad5470..fe2bd515d6cc 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c | |||
@@ -849,14 +849,8 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu) | |||
849 | .done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done), | 849 | .done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done), |
850 | }; | 850 | }; |
851 | INIT_WORK(&c_idle.work, do_fork_idle); | 851 | INIT_WORK(&c_idle.work, do_fork_idle); |
852 | #ifdef CONFIG_X86_64 | ||
853 | /* allocate memory for gdts of secondary cpus. Hotplug is considered */ | ||
854 | if (!cpu_gdt_descr[cpu].address && | ||
855 | !(cpu_gdt_descr[cpu].address = get_zeroed_page(GFP_KERNEL))) { | ||
856 | printk(KERN_ERR "Failed to allocate GDT for CPU %d\n", cpu); | ||
857 | return -1; | ||
858 | } | ||
859 | 852 | ||
853 | #ifdef CONFIG_X86_64 | ||
860 | /* Allocate node local memory for AP pdas */ | 854 | /* Allocate node local memory for AP pdas */ |
861 | if (cpu > 0) { | 855 | if (cpu > 0) { |
862 | boot_error = get_local_pda(cpu); | 856 | boot_error = get_local_pda(cpu); |
@@ -898,7 +892,6 @@ do_rest: | |||
898 | #ifdef CONFIG_X86_32 | 892 | #ifdef CONFIG_X86_32 |
899 | per_cpu(current_task, cpu) = c_idle.idle; | 893 | per_cpu(current_task, cpu) = c_idle.idle; |
900 | init_gdt(cpu); | 894 | init_gdt(cpu); |
901 | early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu); | ||
902 | c_idle.idle->thread.ip = (unsigned long) start_secondary; | 895 | c_idle.idle->thread.ip = (unsigned long) start_secondary; |
903 | /* Stack for startup_32 can be just as for start_secondary onwards */ | 896 | /* Stack for startup_32 can be just as for start_secondary onwards */ |
904 | irq_ctx_init(cpu); | 897 | irq_ctx_init(cpu); |
@@ -908,6 +901,7 @@ do_rest: | |||
908 | initial_code = (unsigned long)start_secondary; | 901 | initial_code = (unsigned long)start_secondary; |
909 | clear_tsk_thread_flag(c_idle.idle, TIF_FORK); | 902 | clear_tsk_thread_flag(c_idle.idle, TIF_FORK); |
910 | #endif | 903 | #endif |
904 | early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu); | ||
911 | stack_start.sp = (void *) c_idle.idle->thread.sp; | 905 | stack_start.sp = (void *) c_idle.idle->thread.sp; |
912 | 906 | ||
913 | /* start_ip had better be page-aligned! */ | 907 | /* start_ip had better be page-aligned! */ |
@@ -1252,8 +1246,8 @@ void __init native_smp_prepare_boot_cpu(void) | |||
1252 | int me = smp_processor_id(); | 1246 | int me = smp_processor_id(); |
1253 | #ifdef CONFIG_X86_32 | 1247 | #ifdef CONFIG_X86_32 |
1254 | init_gdt(me); | 1248 | init_gdt(me); |
1255 | switch_to_new_gdt(); | ||
1256 | #endif | 1249 | #endif |
1250 | switch_to_new_gdt(); | ||
1257 | /* already set me in cpu_online_map in boot_cpu_init() */ | 1251 | /* already set me in cpu_online_map in boot_cpu_init() */ |
1258 | cpu_set(me, cpu_callout_map); | 1252 | cpu_set(me, cpu_callout_map); |
1259 | per_cpu(cpu_state, me) = CPU_ONLINE; | 1253 | per_cpu(cpu_state, me) = CPU_ONLINE; |
diff --git a/arch/x86/kernel/x8664_ksyms_64.c b/arch/x86/kernel/x8664_ksyms_64.c index f6c05d0410fb..2f306a826897 100644 --- a/arch/x86/kernel/x8664_ksyms_64.c +++ b/arch/x86/kernel/x8664_ksyms_64.c | |||
@@ -53,8 +53,3 @@ EXPORT_SYMBOL(init_level4_pgt); | |||
53 | EXPORT_SYMBOL(load_gs_index); | 53 | EXPORT_SYMBOL(load_gs_index); |
54 | 54 | ||
55 | EXPORT_SYMBOL(_proxy_pda); | 55 | EXPORT_SYMBOL(_proxy_pda); |
56 | |||
57 | #ifdef CONFIG_PARAVIRT | ||
58 | /* Virtualized guests may want to use it */ | ||
59 | EXPORT_SYMBOL_GPL(cpu_gdt_descr); | ||
60 | #endif | ||
diff --git a/include/asm-x86/desc.h b/include/asm-x86/desc.h index b3875d4b4fab..07f9f2b17be8 100644 --- a/include/asm-x86/desc.h +++ b/include/asm-x86/desc.h | |||
@@ -29,11 +29,17 @@ static inline void fill_ldt(struct desc_struct *desc, | |||
29 | extern struct desc_ptr idt_descr; | 29 | extern struct desc_ptr idt_descr; |
30 | extern gate_desc idt_table[]; | 30 | extern gate_desc idt_table[]; |
31 | 31 | ||
32 | struct gdt_page { | ||
33 | struct desc_struct gdt[GDT_ENTRIES]; | ||
34 | } __attribute__((aligned(PAGE_SIZE))); | ||
35 | DECLARE_PER_CPU(struct gdt_page, gdt_page); | ||
36 | |||
37 | static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) | ||
38 | { | ||
39 | return per_cpu(gdt_page, cpu).gdt; | ||
40 | } | ||
41 | |||
32 | #ifdef CONFIG_X86_64 | 42 | #ifdef CONFIG_X86_64 |
33 | extern struct desc_struct cpu_gdt_table[GDT_ENTRIES]; | ||
34 | extern struct desc_ptr cpu_gdt_descr[]; | ||
35 | /* the cpu gdt accessor */ | ||
36 | #define get_cpu_gdt_table(x) ((struct desc_struct *)cpu_gdt_descr[x].address) | ||
37 | 43 | ||
38 | static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func, | 44 | static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func, |
39 | unsigned dpl, unsigned ist, unsigned seg) | 45 | unsigned dpl, unsigned ist, unsigned seg) |
@@ -51,16 +57,6 @@ static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func, | |||
51 | } | 57 | } |
52 | 58 | ||
53 | #else | 59 | #else |
54 | struct gdt_page { | ||
55 | struct desc_struct gdt[GDT_ENTRIES]; | ||
56 | } __attribute__((aligned(PAGE_SIZE))); | ||
57 | DECLARE_PER_CPU(struct gdt_page, gdt_page); | ||
58 | |||
59 | static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) | ||
60 | { | ||
61 | return per_cpu(gdt_page, cpu).gdt; | ||
62 | } | ||
63 | |||
64 | static inline void pack_gate(gate_desc *gate, unsigned char type, | 60 | static inline void pack_gate(gate_desc *gate, unsigned char type, |
65 | unsigned long base, unsigned dpl, unsigned flags, | 61 | unsigned long base, unsigned dpl, unsigned flags, |
66 | unsigned short seg) | 62 | unsigned short seg) |
diff --git a/include/asm-x86/segment.h b/include/asm-x86/segment.h index ed5131dd7d92..dfc8601c0892 100644 --- a/include/asm-x86/segment.h +++ b/include/asm-x86/segment.h | |||
@@ -61,18 +61,14 @@ | |||
61 | #define GDT_ENTRY_TLS_MAX (GDT_ENTRY_TLS_MIN + GDT_ENTRY_TLS_ENTRIES - 1) | 61 | #define GDT_ENTRY_TLS_MAX (GDT_ENTRY_TLS_MIN + GDT_ENTRY_TLS_ENTRIES - 1) |
62 | 62 | ||
63 | #define GDT_ENTRY_DEFAULT_USER_CS 14 | 63 | #define GDT_ENTRY_DEFAULT_USER_CS 14 |
64 | #define __USER_CS (GDT_ENTRY_DEFAULT_USER_CS * 8 + 3) | ||
65 | 64 | ||
66 | #define GDT_ENTRY_DEFAULT_USER_DS 15 | 65 | #define GDT_ENTRY_DEFAULT_USER_DS 15 |
67 | #define __USER_DS (GDT_ENTRY_DEFAULT_USER_DS * 8 + 3) | ||
68 | 66 | ||
69 | #define GDT_ENTRY_KERNEL_BASE 12 | 67 | #define GDT_ENTRY_KERNEL_BASE 12 |
70 | 68 | ||
71 | #define GDT_ENTRY_KERNEL_CS (GDT_ENTRY_KERNEL_BASE + 0) | 69 | #define GDT_ENTRY_KERNEL_CS (GDT_ENTRY_KERNEL_BASE + 0) |
72 | #define __KERNEL_CS (GDT_ENTRY_KERNEL_CS * 8) | ||
73 | 70 | ||
74 | #define GDT_ENTRY_KERNEL_DS (GDT_ENTRY_KERNEL_BASE + 1) | 71 | #define GDT_ENTRY_KERNEL_DS (GDT_ENTRY_KERNEL_BASE + 1) |
75 | #define __KERNEL_DS (GDT_ENTRY_KERNEL_DS * 8) | ||
76 | 72 | ||
77 | #define GDT_ENTRY_TSS (GDT_ENTRY_KERNEL_BASE + 4) | 73 | #define GDT_ENTRY_TSS (GDT_ENTRY_KERNEL_BASE + 4) |
78 | #define GDT_ENTRY_LDT (GDT_ENTRY_KERNEL_BASE + 5) | 74 | #define GDT_ENTRY_LDT (GDT_ENTRY_KERNEL_BASE + 5) |
@@ -139,10 +135,11 @@ | |||
139 | #else | 135 | #else |
140 | #include <asm/cache.h> | 136 | #include <asm/cache.h> |
141 | 137 | ||
142 | #define __KERNEL_CS 0x10 | 138 | #define GDT_ENTRY_KERNEL32_CS 1 |
143 | #define __KERNEL_DS 0x18 | 139 | #define GDT_ENTRY_KERNEL_CS 2 |
140 | #define GDT_ENTRY_KERNEL_DS 3 | ||
144 | 141 | ||
145 | #define __KERNEL32_CS 0x08 | 142 | #define __KERNEL32_CS (GDT_ENTRY_KERNEL32_CS * 8) |
146 | 143 | ||
147 | /* | 144 | /* |
148 | * we cannot use the same code segment descriptor for user and kernel | 145 | * we cannot use the same code segment descriptor for user and kernel |
@@ -150,10 +147,10 @@ | |||
150 | * The segment offset needs to contain a RPL. Grr. -AK | 147 | * The segment offset needs to contain a RPL. Grr. -AK |
151 | * GDT layout to get 64bit syscall right (sysret hardcodes gdt offsets) | 148 | * GDT layout to get 64bit syscall right (sysret hardcodes gdt offsets) |
152 | */ | 149 | */ |
153 | 150 | #define GDT_ENTRY_DEFAULT_USER32_CS 4 | |
154 | #define __USER32_CS 0x23 /* 4*8+3 */ | 151 | #define GDT_ENTRY_DEFAULT_USER_DS 5 |
155 | #define __USER_DS 0x2b /* 5*8+3 */ | 152 | #define GDT_ENTRY_DEFAULT_USER_CS 6 |
156 | #define __USER_CS 0x33 /* 6*8+3 */ | 153 | #define __USER32_CS (GDT_ENTRY_DEFAULT_USER32_CS * 8 + 3) |
157 | #define __USER32_DS __USER_DS | 154 | #define __USER32_DS __USER_DS |
158 | 155 | ||
159 | #define GDT_ENTRY_TSS 8 /* needs two entries */ | 156 | #define GDT_ENTRY_TSS 8 /* needs two entries */ |
@@ -175,6 +172,10 @@ | |||
175 | 172 | ||
176 | #endif | 173 | #endif |
177 | 174 | ||
175 | #define __KERNEL_CS (GDT_ENTRY_KERNEL_CS * 8) | ||
176 | #define __KERNEL_DS (GDT_ENTRY_KERNEL_DS * 8) | ||
177 | #define __USER_DS (GDT_ENTRY_DEFAULT_USER_DS* 8 + 3) | ||
178 | #define __USER_CS (GDT_ENTRY_DEFAULT_USER_CS* 8 + 3) | ||
178 | #ifndef CONFIG_PARAVIRT | 179 | #ifndef CONFIG_PARAVIRT |
179 | #define get_kernel_rpl() 0 | 180 | #define get_kernel_rpl() 0 |
180 | #endif | 181 | #endif |