diff options
author | Gerd Hoffmann <kraxel@suse.de> | 2006-06-26 07:56:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-26 13:48:14 -0400 |
commit | d167a51877e94dda73dd656c51f363502309f713 (patch) | |
tree | eb02c2974b61777f575dfdc07d4c2adf83bde434 /include/asm-x86_64/system.h | |
parent | 240cd6a80642da528bfa382ec2ae4e3cb8991ea7 (diff) |
[PATCH] x86_64: x86_64 version of the smp alternative patch.
Changes are largely identical to the i386 version:
* alternative #define are moved to the new alternative.h file.
* one new elf section with pointers to the lock prefixes which can be
nop'ed out for non-smp.
* two new elf sections simliar to the "classic" alternatives to
replace SMP code with simpler UP code.
* fixup headers to use alternative.h instead of defining their own
LOCK / LOCK_PREFIX macros.
The patch reuses the i386 version of the alternatives code to avoid code
duplication. The code in alternatives.c was shuffled around a bit to
reduce the number of #ifdefs needed. It also got some tweaks needed for
x86_64 (vsyscall page handling) and new features (noreplacement option
which was x86_64 only up to now). Debug printk's are changed from
compile-time to runtime.
Loosely based on a early version from Bastian Blank <waldi@debian.org>
Signed-off-by: Gerd Hoffmann <kraxel@suse.de>
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'include/asm-x86_64/system.h')
-rw-r--r-- | include/asm-x86_64/system.h | 86 |
1 files changed, 3 insertions, 83 deletions
diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h index f48e0dad8b3d..68e559f3631c 100644 --- a/include/asm-x86_64/system.h +++ b/include/asm-x86_64/system.h | |||
@@ -3,15 +3,10 @@ | |||
3 | 3 | ||
4 | #include <linux/kernel.h> | 4 | #include <linux/kernel.h> |
5 | #include <asm/segment.h> | 5 | #include <asm/segment.h> |
6 | #include <asm/alternative.h> | ||
6 | 7 | ||
7 | #ifdef __KERNEL__ | 8 | #ifdef __KERNEL__ |
8 | 9 | ||
9 | #ifdef CONFIG_SMP | ||
10 | #define LOCK_PREFIX "lock ; " | ||
11 | #else | ||
12 | #define LOCK_PREFIX "" | ||
13 | #endif | ||
14 | |||
15 | #define __STR(x) #x | 10 | #define __STR(x) #x |
16 | #define STR(x) __STR(x) | 11 | #define STR(x) __STR(x) |
17 | 12 | ||
@@ -34,7 +29,7 @@ | |||
34 | "thread_return:\n\t" \ | 29 | "thread_return:\n\t" \ |
35 | "movq %%gs:%P[pda_pcurrent],%%rsi\n\t" \ | 30 | "movq %%gs:%P[pda_pcurrent],%%rsi\n\t" \ |
36 | "movq %P[thread_info](%%rsi),%%r8\n\t" \ | 31 | "movq %P[thread_info](%%rsi),%%r8\n\t" \ |
37 | LOCK "btr %[tif_fork],%P[ti_flags](%%r8)\n\t" \ | 32 | LOCK_PREFIX "btr %[tif_fork],%P[ti_flags](%%r8)\n\t" \ |
38 | "movq %%rax,%%rdi\n\t" \ | 33 | "movq %%rax,%%rdi\n\t" \ |
39 | "jc ret_from_fork\n\t" \ | 34 | "jc ret_from_fork\n\t" \ |
40 | RESTORE_CONTEXT \ | 35 | RESTORE_CONTEXT \ |
@@ -69,82 +64,6 @@ extern void load_gs_index(unsigned); | |||
69 | ".previous" \ | 64 | ".previous" \ |
70 | : :"r" (value), "r" (0)) | 65 | : :"r" (value), "r" (0)) |
71 | 66 | ||
72 | #ifdef __KERNEL__ | ||
73 | struct alt_instr { | ||
74 | __u8 *instr; /* original instruction */ | ||
75 | __u8 *replacement; | ||
76 | __u8 cpuid; /* cpuid bit set for replacement */ | ||
77 | __u8 instrlen; /* length of original instruction */ | ||
78 | __u8 replacementlen; /* length of new instruction, <= instrlen */ | ||
79 | __u8 pad[5]; | ||
80 | }; | ||
81 | #endif | ||
82 | |||
83 | /* | ||
84 | * Alternative instructions for different CPU types or capabilities. | ||
85 | * | ||
86 | * This allows to use optimized instructions even on generic binary | ||
87 | * kernels. | ||
88 | * | ||
89 | * length of oldinstr must be longer or equal the length of newinstr | ||
90 | * It can be padded with nops as needed. | ||
91 | * | ||
92 | * For non barrier like inlines please define new variants | ||
93 | * without volatile and memory clobber. | ||
94 | */ | ||
95 | #define alternative(oldinstr, newinstr, feature) \ | ||
96 | asm volatile ("661:\n\t" oldinstr "\n662:\n" \ | ||
97 | ".section .altinstructions,\"a\"\n" \ | ||
98 | " .align 8\n" \ | ||
99 | " .quad 661b\n" /* label */ \ | ||
100 | " .quad 663f\n" /* new instruction */ \ | ||
101 | " .byte %c0\n" /* feature bit */ \ | ||
102 | " .byte 662b-661b\n" /* sourcelen */ \ | ||
103 | " .byte 664f-663f\n" /* replacementlen */ \ | ||
104 | ".previous\n" \ | ||
105 | ".section .altinstr_replacement,\"ax\"\n" \ | ||
106 | "663:\n\t" newinstr "\n664:\n" /* replacement */ \ | ||
107 | ".previous" :: "i" (feature) : "memory") | ||
108 | |||
109 | /* | ||
110 | * Alternative inline assembly with input. | ||
111 | * | ||
112 | * Peculiarities: | ||
113 | * No memory clobber here. | ||
114 | * Argument numbers start with 1. | ||
115 | * Best is to use constraints that are fixed size (like (%1) ... "r") | ||
116 | * If you use variable sized constraints like "m" or "g" in the | ||
117 | * replacement make sure to pad to the worst case length. | ||
118 | */ | ||
119 | #define alternative_input(oldinstr, newinstr, feature, input...) \ | ||
120 | asm volatile ("661:\n\t" oldinstr "\n662:\n" \ | ||
121 | ".section .altinstructions,\"a\"\n" \ | ||
122 | " .align 8\n" \ | ||
123 | " .quad 661b\n" /* label */ \ | ||
124 | " .quad 663f\n" /* new instruction */ \ | ||
125 | " .byte %c0\n" /* feature bit */ \ | ||
126 | " .byte 662b-661b\n" /* sourcelen */ \ | ||
127 | " .byte 664f-663f\n" /* replacementlen */ \ | ||
128 | ".previous\n" \ | ||
129 | ".section .altinstr_replacement,\"ax\"\n" \ | ||
130 | "663:\n\t" newinstr "\n664:\n" /* replacement */ \ | ||
131 | ".previous" :: "i" (feature), ##input) | ||
132 | |||
133 | /* Like alternative_input, but with a single output argument */ | ||
134 | #define alternative_io(oldinstr, newinstr, feature, output, input...) \ | ||
135 | asm volatile ("661:\n\t" oldinstr "\n662:\n" \ | ||
136 | ".section .altinstructions,\"a\"\n" \ | ||
137 | " .align 8\n" \ | ||
138 | " .quad 661b\n" /* label */ \ | ||
139 | " .quad 663f\n" /* new instruction */ \ | ||
140 | " .byte %c[feat]\n" /* feature bit */ \ | ||
141 | " .byte 662b-661b\n" /* sourcelen */ \ | ||
142 | " .byte 664f-663f\n" /* replacementlen */ \ | ||
143 | ".previous\n" \ | ||
144 | ".section .altinstr_replacement,\"ax\"\n" \ | ||
145 | "663:\n\t" newinstr "\n664:\n" /* replacement */ \ | ||
146 | ".previous" : output : [feat] "i" (feature), ##input) | ||
147 | |||
148 | /* | 67 | /* |
149 | * Clear and set 'TS' bit respectively | 68 | * Clear and set 'TS' bit respectively |
150 | */ | 69 | */ |
@@ -366,5 +285,6 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, | |||
366 | void cpu_idle_wait(void); | 285 | void cpu_idle_wait(void); |
367 | 286 | ||
368 | extern unsigned long arch_align_stack(unsigned long sp); | 287 | extern unsigned long arch_align_stack(unsigned long sp); |
288 | extern void free_init_pages(char *what, unsigned long begin, unsigned long end); | ||
369 | 289 | ||
370 | #endif | 290 | #endif |