aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86_64/kernel/setup64.c3
-rw-r--r--include/asm-x86_64/pda.h41
2 files changed, 25 insertions, 19 deletions
diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c
index e85cfbb49b63..491361752c70 100644
--- a/arch/x86_64/kernel/setup64.c
+++ b/arch/x86_64/kernel/setup64.c
@@ -121,7 +121,10 @@ void pda_init(int cpu)
121 121
122 /* Setup up data that may be needed in __get_free_pages early */ 122 /* Setup up data that may be needed in __get_free_pages early */
123 asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0)); 123 asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0));
124 /* Memory clobbers used to order PDA accessed */
125 mb();
124 wrmsrl(MSR_GS_BASE, pda); 126 wrmsrl(MSR_GS_BASE, pda);
127 mb();
125 128
126 pda->cpunumber = cpu; 129 pda->cpunumber = cpu;
127 pda->irqcount = -1; 130 pda->irqcount = -1;
diff --git a/include/asm-x86_64/pda.h b/include/asm-x86_64/pda.h
index b47c3df9ed1d..55e21da96e7a 100644
--- a/include/asm-x86_64/pda.h
+++ b/include/asm-x86_64/pda.h
@@ -36,40 +36,43 @@ extern struct x8664_pda boot_cpu_pda[];
36 * There is no fast way to get the base address of the PDA, all the accesses 36 * There is no fast way to get the base address of the PDA, all the accesses
37 * have to mention %fs/%gs. So it needs to be done this Torvaldian way. 37 * have to mention %fs/%gs. So it needs to be done this Torvaldian way.
38 */ 38 */
39#define sizeof_field(type,field) (sizeof(((type *)0)->field))
40#define typeof_field(type,field) typeof(((type *)0)->field)
41
42extern void __bad_pda_field(void); 39extern void __bad_pda_field(void);
43 40
41/* proxy_pda doesn't actually exist, but tell gcc it is accessed
42 for all PDA accesses so it gets read/write dependencies right. */
43extern struct x8664_pda _proxy_pda;
44
44#define pda_offset(field) offsetof(struct x8664_pda, field) 45#define pda_offset(field) offsetof(struct x8664_pda, field)
45 46
46#define pda_to_op(op,field,val) do { \ 47#define pda_to_op(op,field,val) do { \
47 typedef typeof_field(struct x8664_pda, field) T__; \ 48 typedef typeof(_proxy_pda.field) T__; \
48 switch (sizeof_field(struct x8664_pda, field)) { \ 49 switch (sizeof(_proxy_pda.field)) { \
49case 2: \ 50case 2: \
50asm volatile(op "w %0,%%gs:%P1"::"ri" ((T__)val),"i"(pda_offset(field)):"memory"); break; \ 51asm(op "w %1,%%gs:%P2" : "+m" (_proxy_pda.field) : \
52 "ri" ((T__)val),"i"(pda_offset(field))); break; \
51case 4: \ 53case 4: \
52asm volatile(op "l %0,%%gs:%P1"::"ri" ((T__)val),"i"(pda_offset(field)):"memory"); break; \ 54asm(op "l %1,%%gs:%P2" : "+m" (_proxy_pda.field) : \
55 "ri" ((T__)val),"i"(pda_offset(field))); break; \
53case 8: \ 56case 8: \
54asm volatile(op "q %0,%%gs:%P1"::"ri" ((T__)val),"i"(pda_offset(field)):"memory"); break; \ 57asm(op "q %1,%%gs:%P2": "+m" (_proxy_pda.field) : \
55 default: __bad_pda_field(); \ 58 "ri" ((T__)val),"i"(pda_offset(field))); break; \
59default: __bad_pda_field(); \
56 } \ 60 } \
57 } while (0) 61 } while (0)
58 62
59/*
60 * AK: PDA read accesses should be neither volatile nor have an memory clobber.
61 * Unfortunately removing them causes all hell to break lose currently.
62 */
63#define pda_from_op(op,field) ({ \ 63#define pda_from_op(op,field) ({ \
64 typeof_field(struct x8664_pda, field) ret__; \ 64 typeof(_proxy_pda.field) ret__; \
65 switch (sizeof_field(struct x8664_pda, field)) { \ 65 switch (sizeof(_proxy_pda.field)) { \
66case 2: \ 66case 2: \
67asm volatile(op "w %%gs:%P1,%0":"=r" (ret__):"i"(pda_offset(field)):"memory"); break;\ 67asm(op "w %%gs:%P1,%0":"=r" (ret__):\
68 "i" (pda_offset(field)), "m" (_proxy_pda.field)); break;\
68case 4: \ 69case 4: \
69asm volatile(op "l %%gs:%P1,%0":"=r" (ret__):"i"(pda_offset(field)):"memory"); break;\ 70asm(op "l %%gs:%P1,%0":"=r" (ret__):\
71 "i" (pda_offset(field)), "m" (_proxy_pda.field)); break;\
70case 8: \ 72case 8: \
71asm volatile(op "q %%gs:%P1,%0":"=r" (ret__):"i"(pda_offset(field)):"memory"); break;\ 73asm(op "q %%gs:%P1,%0":"=r" (ret__):\
72 default: __bad_pda_field(); \ 74 "i" (pda_offset(field)), "m" (_proxy_pda.field)); break;\
75default: __bad_pda_field(); \
73 } \ 76 } \
74 ret__; }) 77 ret__; })
75 78