aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Machek <pavel@suse.cz>2008-04-10 17:28:10 -0400
committerIngo Molnar <mingo@elte.hu>2008-04-17 11:41:37 -0400
commite44b7b7525ad9d43163ab5e60c784325419e0ea6 (patch)
treee2918917a97b4c9de4367e8778ed78afc762b9f8
parentf49688d459c5eaa62db3597cbfd3cb13e361d415 (diff)
x86: move suspend wakeup code to C
Move wakeup code to .c, so that video mode setting code can be shared between boot and wakeup. Remove nasty assembly code in 64-bit case by re-using trampoline code. Stack setup was fixed to clear high 16bits of %esp, maybe that fixes some machines. .c code sharing and morse code was done H. Peter Anvin, Sam Ravnborg reviewed kbuild related stuff, and it seems okay to him. Rafael did some cleanups. [rjw: * Made the patch stop breaking compilation on x86-32 * Added arch/x86/kernel/acpi/sleep.h * Got rid of compiler warnings in arch/x86/kernel/acpi/sleep.c * Fixed 32-bit compilation on x86-64 systems * Added include/asm-x86/trampoline.h and fixed the non-SMP compilation on 64-bit x86 * Removed arch/x86/kernel/acpi/sleep_32.c which was not used * Fixed some breakage caused by the integration of smpboot.c done under us in the meantime] Signed-off-by: Pavel Machek <pavel@suse.cz> Signed-off-by: H. Peter Anvin <hpa@zytor.com> Reviewed-by: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/Kconfig2
-rw-r--r--arch/x86/boot/Makefile2
-rw-r--r--arch/x86/boot/boot.h5
-rw-r--r--arch/x86/boot/video-bios.c6
-rw-r--r--arch/x86/boot/video-mode.c173
-rw-r--r--arch/x86/boot/video-vesa.c8
-rw-r--r--arch/x86/boot/video-vga.c12
-rw-r--r--arch/x86/boot/video.c157
-rw-r--r--arch/x86/kernel/acpi/Makefile9
-rw-r--r--arch/x86/kernel/acpi/realmode/Makefile57
-rw-r--r--arch/x86/kernel/acpi/realmode/copy.S1
-rw-r--r--arch/x86/kernel/acpi/realmode/video-bios.c1
-rw-r--r--arch/x86/kernel/acpi/realmode/video-mode.c1
-rw-r--r--arch/x86/kernel/acpi/realmode/video-vesa.c1
-rw-r--r--arch/x86/kernel/acpi/realmode/video-vga.c1
-rw-r--r--arch/x86/kernel/acpi/realmode/wakemain.c81
-rw-r--r--arch/x86/kernel/acpi/realmode/wakeup.S113
-rw-r--r--arch/x86/kernel/acpi/realmode/wakeup.h36
-rw-r--r--arch/x86/kernel/acpi/realmode/wakeup.lds.S61
-rw-r--r--arch/x86/kernel/acpi/sleep.c71
-rw-r--r--arch/x86/kernel/acpi/sleep.h16
-rw-r--r--arch/x86/kernel/acpi/sleep_32.c40
-rw-r--r--arch/x86/kernel/acpi/wakeup_32.S247
-rw-r--r--arch/x86/kernel/acpi/wakeup_64.S313
-rw-r--r--arch/x86/kernel/acpi/wakeup_rm.S10
-rw-r--r--arch/x86/kernel/e820_64.c5
-rw-r--r--arch/x86/kernel/head_64.S4
-rw-r--r--arch/x86/kernel/setup_32.c4
-rw-r--r--arch/x86/kernel/setup_64.c1
-rw-r--r--arch/x86/kernel/smpboot.c6
-rw-r--r--arch/x86/kernel/trampoline_64.S5
-rw-r--r--arch/x86/mach-voyager/voyager_smp.c1
-rw-r--r--include/asm-x86/smp.h13
-rw-r--r--include/asm-x86/trampoline.h21
34 files changed, 711 insertions, 773 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 0a7193ae45ed..4e32b6f7d31a 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -181,7 +181,7 @@ config X86_BIOS_REBOOT
181 181
182config X86_TRAMPOLINE 182config X86_TRAMPOLINE
183 bool 183 bool
184 depends on X86_SMP || (X86_VOYAGER && SMP) 184 depends on X86_SMP || (X86_VOYAGER && SMP) || (64BIT && ACPI_SLEEP)
185 default y 185 default y
186 186
187config KTIME_SCALAR 187config KTIME_SCALAR
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index 9695affeb584..7ee102f9c4f8 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -30,7 +30,7 @@ subdir- := compressed
30 30
31setup-y += a20.o cmdline.o copy.o cpu.o cpucheck.o edd.o 31setup-y += a20.o cmdline.o copy.o cpu.o cpucheck.o edd.o
32setup-y += header.o main.o mca.o memory.o pm.o pmjump.o 32setup-y += header.o main.o mca.o memory.o pm.o pmjump.o
33setup-y += printf.o string.o tty.o video.o version.o 33setup-y += printf.o string.o tty.o video.o video-mode.o version.o
34setup-$(CONFIG_X86_APM_BOOT) += apm.o 34setup-$(CONFIG_X86_APM_BOOT) += apm.o
35setup-$(CONFIG_X86_VOYAGER) += voyager.o 35setup-$(CONFIG_X86_VOYAGER) += voyager.o
36 36
diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
index 7822a4983da2..09578070bfba 100644
--- a/arch/x86/boot/boot.h
+++ b/arch/x86/boot/boot.h
@@ -286,6 +286,11 @@ int getchar_timeout(void);
286/* video.c */ 286/* video.c */
287void set_video(void); 287void set_video(void);
288 288
289/* video-mode.c */
290int set_mode(u16 mode);
291int mode_defined(u16 mode);
292void probe_cards(int unsafe);
293
289/* video-vesa.c */ 294/* video-vesa.c */
290void vesa_store_edid(void); 295void vesa_store_edid(void);
291 296
diff --git a/arch/x86/boot/video-bios.c b/arch/x86/boot/video-bios.c
index ff664a117096..39e247e96172 100644
--- a/arch/x86/boot/video-bios.c
+++ b/arch/x86/boot/video-bios.c
@@ -50,6 +50,7 @@ static int set_bios_mode(u8 mode)
50 if (new_mode == mode) 50 if (new_mode == mode)
51 return 0; /* Mode change OK */ 51 return 0; /* Mode change OK */
52 52
53#ifndef _WAKEUP
53 if (new_mode != boot_params.screen_info.orig_video_mode) { 54 if (new_mode != boot_params.screen_info.orig_video_mode) {
54 /* Mode setting failed, but we didn't end up where we 55 /* Mode setting failed, but we didn't end up where we
55 started. That's bad. Try to revert to the original 56 started. That's bad. Try to revert to the original
@@ -59,13 +60,18 @@ static int set_bios_mode(u8 mode)
59 : "+a" (ax) 60 : "+a" (ax)
60 : : "ebx", "ecx", "edx", "esi", "edi"); 61 : : "ebx", "ecx", "edx", "esi", "edi");
61 } 62 }
63#endif
62 return -1; 64 return -1;
63} 65}
64 66
65static int bios_probe(void) 67static int bios_probe(void)
66{ 68{
67 u8 mode; 69 u8 mode;
70#ifdef _WAKEUP
71 u8 saved_mode = 0x03;
72#else
68 u8 saved_mode = boot_params.screen_info.orig_video_mode; 73 u8 saved_mode = boot_params.screen_info.orig_video_mode;
74#endif
69 u16 crtc; 75 u16 crtc;
70 struct mode_info *mi; 76 struct mode_info *mi;
71 int nmodes = 0; 77 int nmodes = 0;
diff --git a/arch/x86/boot/video-mode.c b/arch/x86/boot/video-mode.c
new file mode 100644
index 000000000000..748e8d06290a
--- /dev/null
+++ b/arch/x86/boot/video-mode.c
@@ -0,0 +1,173 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007-2008 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/video-mode.c
13 *
14 * Set the video mode. This is separated out into a different
15 * file in order to be shared with the ACPI wakeup code.
16 */
17
18#include "boot.h"
19#include "video.h"
20#include "vesa.h"
21
22/*
23 * Common variables
24 */
25int adapter; /* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */
26u16 video_segment;
27int force_x, force_y; /* Don't query the BIOS for cols/rows */
28
29int do_restore; /* Screen contents changed during mode flip */
30int graphic_mode; /* Graphic mode with linear frame buffer */
31
32/* Probe the video drivers and have them generate their mode lists. */
33void probe_cards(int unsafe)
34{
35 struct card_info *card;
36 static u8 probed[2];
37
38 if (probed[unsafe])
39 return;
40
41 probed[unsafe] = 1;
42
43 for (card = video_cards; card < video_cards_end; card++) {
44 if (card->unsafe == unsafe) {
45 if (card->probe)
46 card->nmodes = card->probe();
47 else
48 card->nmodes = 0;
49 }
50 }
51}
52
53/* Test if a mode is defined */
54int mode_defined(u16 mode)
55{
56 struct card_info *card;
57 struct mode_info *mi;
58 int i;
59
60 for (card = video_cards; card < video_cards_end; card++) {
61 mi = card->modes;
62 for (i = 0; i < card->nmodes; i++, mi++) {
63 if (mi->mode == mode)
64 return 1;
65 }
66 }
67
68 return 0;
69}
70
71/* Set mode (without recalc) */
72static int raw_set_mode(u16 mode, u16 *real_mode)
73{
74 int nmode, i;
75 struct card_info *card;
76 struct mode_info *mi;
77
78 /* Drop the recalc bit if set */
79 mode &= ~VIDEO_RECALC;
80
81 /* Scan for mode based on fixed ID, position, or resolution */
82 nmode = 0;
83 for (card = video_cards; card < video_cards_end; card++) {
84 mi = card->modes;
85 for (i = 0; i < card->nmodes; i++, mi++) {
86 int visible = mi->x || mi->y;
87
88 if ((mode == nmode && visible) ||
89 mode == mi->mode ||
90 mode == (mi->y << 8)+mi->x) {
91 *real_mode = mi->mode;
92 return card->set_mode(mi);
93 }
94
95 if (visible)
96 nmode++;
97 }
98 }
99
100 /* Nothing found? Is it an "exceptional" (unprobed) mode? */
101 for (card = video_cards; card < video_cards_end; card++) {
102 if (mode >= card->xmode_first &&
103 mode < card->xmode_first+card->xmode_n) {
104 struct mode_info mix;
105 *real_mode = mix.mode = mode;
106 mix.x = mix.y = 0;
107 return card->set_mode(&mix);
108 }
109 }
110
111 /* Otherwise, failure... */
112 return -1;
113}
114
115/*
116 * Recalculate the vertical video cutoff (hack!)
117 */
118static void vga_recalc_vertical(void)
119{
120 unsigned int font_size, rows;
121 u16 crtc;
122 u8 pt, ov;
123
124 set_fs(0);
125 font_size = rdfs8(0x485); /* BIOS: font size (pixels) */
126 rows = force_y ? force_y : rdfs8(0x484)+1; /* Text rows */
127
128 rows *= font_size; /* Visible scan lines */
129 rows--; /* ... minus one */
130
131 crtc = vga_crtc();
132
133 pt = in_idx(crtc, 0x11);
134 pt &= ~0x80; /* Unlock CR0-7 */
135 out_idx(pt, crtc, 0x11);
136
137 out_idx((u8)rows, crtc, 0x12); /* Lower height register */
138
139 ov = in_idx(crtc, 0x07); /* Overflow register */
140 ov &= 0xbd;
141 ov |= (rows >> (8-1)) & 0x02;
142 ov |= (rows >> (9-6)) & 0x40;
143 out_idx(ov, crtc, 0x07);
144}
145
146/* Set mode (with recalc if specified) */
147int set_mode(u16 mode)
148{
149 int rv;
150 u16 real_mode;
151
152 /* Very special mode numbers... */
153 if (mode == VIDEO_CURRENT_MODE)
154 return 0; /* Nothing to do... */
155 else if (mode == NORMAL_VGA)
156 mode = VIDEO_80x25;
157 else if (mode == EXTENDED_VGA)
158 mode = VIDEO_8POINT;
159
160 rv = raw_set_mode(mode, &real_mode);
161 if (rv)
162 return rv;
163
164 if (mode & VIDEO_RECALC)
165 vga_recalc_vertical();
166
167 /* Save the canonical mode number for the kernel, not
168 an alias, size specification or menu position */
169#ifndef _WAKEUP
170 boot_params.hdr.vid_mode = real_mode;
171#endif
172 return 0;
173}
diff --git a/arch/x86/boot/video-vesa.c b/arch/x86/boot/video-vesa.c
index 419b5c273374..5d5a3f6e8b5c 100644
--- a/arch/x86/boot/video-vesa.c
+++ b/arch/x86/boot/video-vesa.c
@@ -24,7 +24,11 @@ static struct vesa_mode_info vminfo;
24 24
25__videocard video_vesa; 25__videocard video_vesa;
26 26
27#ifndef _WAKEUP
27static void vesa_store_mode_params_graphics(void); 28static void vesa_store_mode_params_graphics(void);
29#else /* _WAKEUP */
30static inline void vesa_store_mode_params_graphics(void) {}
31#endif /* _WAKEUP */
28 32
29static int vesa_probe(void) 33static int vesa_probe(void)
30{ 34{
@@ -165,6 +169,8 @@ static int vesa_set_mode(struct mode_info *mode)
165} 169}
166 170
167 171
172#ifndef _WAKEUP
173
168/* Switch DAC to 8-bit mode */ 174/* Switch DAC to 8-bit mode */
169static void vesa_dac_set_8bits(void) 175static void vesa_dac_set_8bits(void)
170{ 176{
@@ -288,6 +294,8 @@ void vesa_store_edid(void)
288#endif /* CONFIG_FIRMWARE_EDID */ 294#endif /* CONFIG_FIRMWARE_EDID */
289} 295}
290 296
297#endif /* not _WAKEUP */
298
291__videocard video_vesa = 299__videocard video_vesa =
292{ 300{
293 .card_name = "VESA", 301 .card_name = "VESA",
diff --git a/arch/x86/boot/video-vga.c b/arch/x86/boot/video-vga.c
index 7259387b7d19..330d6589a2ad 100644
--- a/arch/x86/boot/video-vga.c
+++ b/arch/x86/boot/video-vga.c
@@ -210,6 +210,8 @@ static int vga_set_mode(struct mode_info *mode)
210 */ 210 */
211static int vga_probe(void) 211static int vga_probe(void)
212{ 212{
213 u16 ega_bx;
214
213 static const char *card_name[] = { 215 static const char *card_name[] = {
214 "CGA/MDA/HGC", "EGA", "VGA" 216 "CGA/MDA/HGC", "EGA", "VGA"
215 }; 217 };
@@ -226,12 +228,16 @@ static int vga_probe(void)
226 u8 vga_flag; 228 u8 vga_flag;
227 229
228 asm(INT10 230 asm(INT10
229 : "=b" (boot_params.screen_info.orig_video_ega_bx) 231 : "=b" (ega_bx)
230 : "a" (0x1200), "b" (0x10) /* Check EGA/VGA */ 232 : "a" (0x1200), "b" (0x10) /* Check EGA/VGA */
231 : "ecx", "edx", "esi", "edi"); 233 : "ecx", "edx", "esi", "edi");
232 234
235#ifndef _WAKEUP
236 boot_params.screen_info.orig_video_ega_bx = ega_bx;
237#endif
238
233 /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */ 239 /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */
234 if ((u8)boot_params.screen_info.orig_video_ega_bx != 0x10) { 240 if ((u8)ega_bx != 0x10) {
235 /* EGA/VGA */ 241 /* EGA/VGA */
236 asm(INT10 242 asm(INT10
237 : "=a" (vga_flag) 243 : "=a" (vga_flag)
@@ -240,7 +246,9 @@ static int vga_probe(void)
240 246
241 if (vga_flag == 0x1a) { 247 if (vga_flag == 0x1a) {
242 adapter = ADAPTER_VGA; 248 adapter = ADAPTER_VGA;
249#ifndef _WAKEUP
243 boot_params.screen_info.orig_video_isVGA = 1; 250 boot_params.screen_info.orig_video_isVGA = 1;
251#endif
244 } else { 252 } else {
245 adapter = ADAPTER_EGA; 253 adapter = ADAPTER_EGA;
246 } 254 }
diff --git a/arch/x86/boot/video.c b/arch/x86/boot/video.c
index 696d08f3843c..c1c47ba069ef 100644
--- a/arch/x86/boot/video.c
+++ b/arch/x86/boot/video.c
@@ -18,21 +18,6 @@
18#include "video.h" 18#include "video.h"
19#include "vesa.h" 19#include "vesa.h"
20 20
21/*
22 * Mode list variables
23 */
24static struct card_info cards[]; /* List of cards to probe for */
25
26/*
27 * Common variables
28 */
29int adapter; /* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */
30u16 video_segment;
31int force_x, force_y; /* Don't query the BIOS for cols/rows */
32
33int do_restore = 0; /* Screen contents changed during mode flip */
34int graphic_mode; /* Graphic mode with linear frame buffer */
35
36static void store_cursor_position(void) 21static void store_cursor_position(void)
37{ 22{
38 u16 curpos; 23 u16 curpos;
@@ -107,147 +92,6 @@ static void store_mode_params(void)
107 boot_params.screen_info.orig_video_lines = y; 92 boot_params.screen_info.orig_video_lines = y;
108} 93}
109 94
110/* Probe the video drivers and have them generate their mode lists. */
111static void probe_cards(int unsafe)
112{
113 struct card_info *card;
114 static u8 probed[2];
115
116 if (probed[unsafe])
117 return;
118
119 probed[unsafe] = 1;
120
121 for (card = video_cards; card < video_cards_end; card++) {
122 if (card->unsafe == unsafe) {
123 if (card->probe)
124 card->nmodes = card->probe();
125 else
126 card->nmodes = 0;
127 }
128 }
129}
130
131/* Test if a mode is defined */
132int mode_defined(u16 mode)
133{
134 struct card_info *card;
135 struct mode_info *mi;
136 int i;
137
138 for (card = video_cards; card < video_cards_end; card++) {
139 mi = card->modes;
140 for (i = 0; i < card->nmodes; i++, mi++) {
141 if (mi->mode == mode)
142 return 1;
143 }
144 }
145
146 return 0;
147}
148
149/* Set mode (without recalc) */
150static int raw_set_mode(u16 mode, u16 *real_mode)
151{
152 int nmode, i;
153 struct card_info *card;
154 struct mode_info *mi;
155
156 /* Drop the recalc bit if set */
157 mode &= ~VIDEO_RECALC;
158
159 /* Scan for mode based on fixed ID, position, or resolution */
160 nmode = 0;
161 for (card = video_cards; card < video_cards_end; card++) {
162 mi = card->modes;
163 for (i = 0; i < card->nmodes; i++, mi++) {
164 int visible = mi->x || mi->y;
165
166 if ((mode == nmode && visible) ||
167 mode == mi->mode ||
168 mode == (mi->y << 8)+mi->x) {
169 *real_mode = mi->mode;
170 return card->set_mode(mi);
171 }
172
173 if (visible)
174 nmode++;
175 }
176 }
177
178 /* Nothing found? Is it an "exceptional" (unprobed) mode? */
179 for (card = video_cards; card < video_cards_end; card++) {
180 if (mode >= card->xmode_first &&
181 mode < card->xmode_first+card->xmode_n) {
182 struct mode_info mix;
183 *real_mode = mix.mode = mode;
184 mix.x = mix.y = 0;
185 return card->set_mode(&mix);
186 }
187 }
188
189 /* Otherwise, failure... */
190 return -1;
191}
192
193/*
194 * Recalculate the vertical video cutoff (hack!)
195 */
196static void vga_recalc_vertical(void)
197{
198 unsigned int font_size, rows;
199 u16 crtc;
200 u8 pt, ov;
201
202 set_fs(0);
203 font_size = rdfs8(0x485); /* BIOS: font size (pixels) */
204 rows = force_y ? force_y : rdfs8(0x484)+1; /* Text rows */
205
206 rows *= font_size; /* Visible scan lines */
207 rows--; /* ... minus one */
208
209 crtc = vga_crtc();
210
211 pt = in_idx(crtc, 0x11);
212 pt &= ~0x80; /* Unlock CR0-7 */
213 out_idx(pt, crtc, 0x11);
214
215 out_idx((u8)rows, crtc, 0x12); /* Lower height register */
216
217 ov = in_idx(crtc, 0x07); /* Overflow register */
218 ov &= 0xbd;
219 ov |= (rows >> (8-1)) & 0x02;
220 ov |= (rows >> (9-6)) & 0x40;
221 out_idx(ov, crtc, 0x07);
222}
223
224/* Set mode (with recalc if specified) */
225static int set_mode(u16 mode)
226{
227 int rv;
228 u16 real_mode;
229
230 /* Very special mode numbers... */
231 if (mode == VIDEO_CURRENT_MODE)
232 return 0; /* Nothing to do... */
233 else if (mode == NORMAL_VGA)
234 mode = VIDEO_80x25;
235 else if (mode == EXTENDED_VGA)
236 mode = VIDEO_8POINT;
237
238 rv = raw_set_mode(mode, &real_mode);
239 if (rv)
240 return rv;
241
242 if (mode & VIDEO_RECALC)
243 vga_recalc_vertical();
244
245 /* Save the canonical mode number for the kernel, not
246 an alias, size specification or menu position */
247 boot_params.hdr.vid_mode = real_mode;
248 return 0;
249}
250
251static unsigned int get_entry(void) 95static unsigned int get_entry(void)
252{ 96{
253 char entry_buf[4]; 97 char entry_buf[4];
@@ -486,6 +330,7 @@ void set_video(void)
486 printf("Undefined video mode number: %x\n", mode); 330 printf("Undefined video mode number: %x\n", mode);
487 mode = ASK_VGA; 331 mode = ASK_VGA;
488 } 332 }
333 boot_params.hdr.vid_mode = mode;
489 vesa_store_edid(); 334 vesa_store_edid();
490 store_mode_params(); 335 store_mode_params();
491 336
diff --git a/arch/x86/kernel/acpi/Makefile b/arch/x86/kernel/acpi/Makefile
index 19d3d6e9d09b..7335959b6aff 100644
--- a/arch/x86/kernel/acpi/Makefile
+++ b/arch/x86/kernel/acpi/Makefile
@@ -1,7 +1,14 @@
1subdir- := realmode
2
1obj-$(CONFIG_ACPI) += boot.o 3obj-$(CONFIG_ACPI) += boot.o
2obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o 4obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_rm.o wakeup_$(BITS).o
3 5
4ifneq ($(CONFIG_ACPI_PROCESSOR),) 6ifneq ($(CONFIG_ACPI_PROCESSOR),)
5obj-y += cstate.o processor.o 7obj-y += cstate.o processor.o
6endif 8endif
7 9
10$(obj)/wakeup_rm.o: $(obj)/realmode/wakeup.bin
11
12$(obj)/realmode/wakeup.bin: FORCE
13 $(Q)$(MAKE) $(build)=$(obj)/realmode $@
14
diff --git a/arch/x86/kernel/acpi/realmode/Makefile b/arch/x86/kernel/acpi/realmode/Makefile
new file mode 100644
index 000000000000..092900854acc
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/Makefile
@@ -0,0 +1,57 @@
1#
2# arch/x86/kernel/acpi/realmode/Makefile
3#
4# This file is subject to the terms and conditions of the GNU General Public
5# License. See the file "COPYING" in the main directory of this archive
6# for more details.
7#
8
9targets := wakeup.bin wakeup.elf
10
11wakeup-y += wakeup.o wakemain.o video-mode.o copy.o
12
13# The link order of the video-*.o modules can matter. In particular,
14# video-vga.o *must* be listed first, followed by video-vesa.o.
15# Hardware-specific drivers should follow in the order they should be
16# probed, and video-bios.o should typically be last.
17wakeup-y += video-vga.o
18wakeup-y += video-vesa.o
19wakeup-y += video-bios.o
20
21targets += $(wakeup-y)
22
23bootsrc := $(src)/../../../boot
24
25# ---------------------------------------------------------------------------
26
27# How to compile the 16-bit code. Note we always compile for -march=i386,
28# that way we can complain to the user if the CPU is insufficient.
29# Compile with _SETUP since this is similar to the boot-time setup code.
30KBUILD_CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D_WAKEUP -D__KERNEL__ \
31 -I$(srctree)/$(bootsrc) \
32 $(cflags-y) \
33 -Wall -Wstrict-prototypes \
34 -march=i386 -mregparm=3 \
35 -include $(srctree)/$(bootsrc)/code16gcc.h \
36 -fno-strict-aliasing -fomit-frame-pointer \
37 $(call cc-option, -ffreestanding) \
38 $(call cc-option, -fno-toplevel-reorder,\
39 $(call cc-option, -fno-unit-at-a-time)) \
40 $(call cc-option, -fno-stack-protector) \
41 $(call cc-option, -mpreferred-stack-boundary=2)
42KBUILD_CFLAGS += $(call cc-option, -m32)
43KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
44
45WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y))
46
47LDFLAGS_wakeup.elf := -T
48
49CPPFLAGS_wakeup.lds += -P -C
50
51$(obj)/wakeup.elf: $(src)/wakeup.lds $(WAKEUP_OBJS) FORCE
52 $(call if_changed,ld)
53
54OBJCOPYFLAGS_wakeup.bin := -O binary
55
56$(obj)/wakeup.bin: $(obj)/wakeup.elf FORCE
57 $(call if_changed,objcopy)
diff --git a/arch/x86/kernel/acpi/realmode/copy.S b/arch/x86/kernel/acpi/realmode/copy.S
new file mode 100644
index 000000000000..dc59ebee69d8
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/copy.S
@@ -0,0 +1 @@
#include "../../../boot/copy.S"
diff --git a/arch/x86/kernel/acpi/realmode/video-bios.c b/arch/x86/kernel/acpi/realmode/video-bios.c
new file mode 100644
index 000000000000..7deabc144a27
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/video-bios.c
@@ -0,0 +1 @@
#include "../../../boot/video-bios.c"
diff --git a/arch/x86/kernel/acpi/realmode/video-mode.c b/arch/x86/kernel/acpi/realmode/video-mode.c
new file mode 100644
index 000000000000..328ad209f113
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/video-mode.c
@@ -0,0 +1 @@
#include "../../../boot/video-mode.c"
diff --git a/arch/x86/kernel/acpi/realmode/video-vesa.c b/arch/x86/kernel/acpi/realmode/video-vesa.c
new file mode 100644
index 000000000000..9dbb9672226a
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/video-vesa.c
@@ -0,0 +1 @@
#include "../../../boot/video-vesa.c"
diff --git a/arch/x86/kernel/acpi/realmode/video-vga.c b/arch/x86/kernel/acpi/realmode/video-vga.c
new file mode 100644
index 000000000000..bcc81255f374
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/video-vga.c
@@ -0,0 +1 @@
#include "../../../boot/video-vga.c"
diff --git a/arch/x86/kernel/acpi/realmode/wakemain.c b/arch/x86/kernel/acpi/realmode/wakemain.c
new file mode 100644
index 000000000000..883962d9eef2
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/wakemain.c
@@ -0,0 +1,81 @@
1#include "wakeup.h"
2#include "boot.h"
3
4static void udelay(int loops)
5{
6 while (loops--)
7 io_delay(); /* Approximately 1 us */
8}
9
10static void beep(unsigned int hz)
11{
12 u8 enable;
13
14 if (!hz) {
15 enable = 0x00; /* Turn off speaker */
16 } else {
17 u16 div = 1193181/hz;
18
19 outb(0xb6, 0x43); /* Ctr 2, squarewave, load, binary */
20 io_delay();
21 outb(div, 0x42); /* LSB of counter */
22 io_delay();
23 outb(div >> 8, 0x42); /* MSB of counter */
24 io_delay();
25
26 enable = 0x03; /* Turn on speaker */
27 }
28 inb(0x61); /* Dummy read of System Control Port B */
29 io_delay();
30 outb(enable, 0x61); /* Enable timer 2 output to speaker */
31 io_delay();
32}
33
34#define DOT_HZ 880
35#define DASH_HZ 587
36#define US_PER_DOT 125000
37
38/* Okay, this is totally silly, but it's kind of fun. */
39static void send_morse(const char *pattern)
40{
41 char s;
42
43 while ((s = *pattern++)) {
44 switch (s) {
45 case '.':
46 beep(DOT_HZ);
47 udelay(US_PER_DOT);
48 beep(0);
49 udelay(US_PER_DOT);
50 break;
51 case '-':
52 beep(DASH_HZ);
53 udelay(US_PER_DOT * 3);
54 beep(0);
55 udelay(US_PER_DOT);
56 break;
57 default: /* Assume it's a space */
58 udelay(US_PER_DOT * 3);
59 break;
60 }
61 }
62}
63
64void main(void)
65{
66 /* Kill machine if structures are wrong */
67 if (wakeup_header.real_magic != 0x12345678)
68 while (1);
69
70 if (wakeup_header.realmode_flags & 4)
71 send_morse("...-");
72
73 if (wakeup_header.realmode_flags & 1)
74 asm volatile("lcallw $0xc000,$3");
75
76 if (wakeup_header.realmode_flags & 2) {
77 /* Need to call BIOS */
78 probe_cards(0);
79 set_mode(wakeup_header.video_mode);
80 }
81}
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.S b/arch/x86/kernel/acpi/realmode/wakeup.S
new file mode 100644
index 000000000000..f9b77fb37e5b
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/wakeup.S
@@ -0,0 +1,113 @@
1/*
2 * ACPI wakeup real mode startup stub
3 */
4#include <asm/segment.h>
5#include <asm/msr-index.h>
6#include <asm/page.h>
7#include <asm/pgtable.h>
8
9 .code16
10 .section ".header", "a"
11
12/* This should match the structure in wakeup.h */
13 .globl wakeup_header
14wakeup_header:
15video_mode: .short 0 /* Video mode number */
16pmode_return: .byte 0x66, 0xea /* ljmpl */
17 .long 0 /* offset goes here */
18 .short __KERNEL_CS
19pmode_cr0: .long 0 /* Saved %cr0 */
20pmode_cr3: .long 0 /* Saved %cr3 */
21pmode_cr4: .long 0 /* Saved %cr4 */
22pmode_efer: .quad 0 /* Saved EFER */
23pmode_gdt: .quad 0
24realmode_flags: .long 0
25real_magic: .long 0
26trampoline_segment: .word 0
27signature: .long 0x51ee1111
28
29 .text
30 .globl _start
31 .code16
32wakeup_code:
33_start:
34 cli
35 cld
36
37 /* Set up segments */
38 movw %cs, %ax
39 movw %ax, %ds
40 movw %ax, %es
41 movw %ax, %ss
42
43 movl $wakeup_stack_end, %esp
44
45 /* Clear the EFLAGS */
46 pushl $0
47 popfl
48
49 /* Check header signature... */
50 movl signature, %eax
51 cmpl $0x51ee1111, %eax
52 jne bogus_real_magic
53
54 /* Check we really have everything... */
55 movl end_signature, %eax
56 cmpl $0x65a22c82, %eax
57 jne bogus_real_magic
58
59 /* Call the C code */
60 calll main
61
62 /* Do any other stuff... */
63
64#ifndef CONFIG_64BIT
65 /* This could also be done in C code... */
66 movl pmode_cr3, %eax
67 movl %eax, %cr3
68
69 movl pmode_cr4, %ecx
70 jecxz 1f
71 movl %ecx, %cr4
721:
73 movl pmode_efer, %eax
74 movl pmode_efer + 4, %edx
75 movl %eax, %ecx
76 orl %edx, %ecx
77 jz 1f
78 movl $0xc0000080, %ecx
79 wrmsr
801:
81
82 lgdtl pmode_gdt
83
84 /* This really couldn't... */
85 movl pmode_cr0, %eax
86 movl %eax, %cr0
87 jmp pmode_return
88#else
89 pushw $0
90 pushw trampoline_segment
91 pushw $0
92 lret
93#endif
94
95bogus_real_magic:
961:
97 hlt
98 jmp 1b
99
100 .data
101 .balign 4
102 .globl HEAP, heap_end
103HEAP:
104 .long wakeup_heap
105heap_end:
106 .long wakeup_stack
107
108 .bss
109wakeup_heap:
110 .space 2048
111wakeup_stack:
112 .space 2048
113wakeup_stack_end:
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.h b/arch/x86/kernel/acpi/realmode/wakeup.h
new file mode 100644
index 000000000000..ef8166fe8020
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/wakeup.h
@@ -0,0 +1,36 @@
1/*
2 * Definitions for the wakeup data structure at the head of the
3 * wakeup code.
4 */
5
6#ifndef ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
7#define ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
8
9#ifndef __ASSEMBLY__
10#include <linux/types.h>
11
12/* This must match data at wakeup.S */
13struct wakeup_header {
14 u16 video_mode; /* Video mode number */
15 u16 _jmp1; /* ljmpl opcode, 32-bit only */
16 u32 pmode_entry; /* Protected mode resume point, 32-bit only */
17 u16 _jmp2; /* CS value, 32-bit only */
18 u32 pmode_cr0; /* Protected mode cr0 */
19 u32 pmode_cr3; /* Protected mode cr3 */
20 u32 pmode_cr4; /* Protected mode cr4 */
21 u32 pmode_efer_low; /* Protected mode EFER */
22 u32 pmode_efer_high;
23 u64 pmode_gdt;
24 u32 realmode_flags;
25 u32 real_magic;
26 u16 trampoline_segment; /* segment with trampoline code, 64-bit only */
27 u32 signature; /* To check we have correct structure */
28} __attribute__((__packed__));
29
30extern struct wakeup_header wakeup_header;
31#endif
32
33#define HEADER_OFFSET 0x3f00
34#define WAKEUP_SIZE 0x4000
35
36#endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.lds.S b/arch/x86/kernel/acpi/realmode/wakeup.lds.S
new file mode 100644
index 000000000000..22fab6c4be15
--- /dev/null
+++ b/arch/x86/kernel/acpi/realmode/wakeup.lds.S
@@ -0,0 +1,61 @@
1/*
2 * wakeup.ld
3 *
4 * Linker script for the real-mode wakeup code
5 */
6#undef i386
7#include "wakeup.h"
8
9OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
10OUTPUT_ARCH(i386)
11ENTRY(_start)
12
13SECTIONS
14{
15 . = HEADER_OFFSET;
16 .header : {
17 *(.header)
18 }
19
20 . = 0;
21 .text : {
22 *(.text*)
23 }
24
25 . = ALIGN(16);
26 .rodata : {
27 *(.rodata*)
28 }
29
30 .videocards : {
31 video_cards = .;
32 *(.videocards)
33 video_cards_end = .;
34 }
35
36 . = ALIGN(16);
37 .data : {
38 *(.data*)
39 }
40
41 .signature : {
42 end_signature = .;
43 LONG(0x65a22c82)
44 }
45
46 . = ALIGN(16);
47 .bss : {
48 __bss_start = .;
49 *(.bss)
50 __bss_end = .;
51 }
52
53 . = ALIGN(16);
54 _end = .;
55
56 /DISCARD/ : {
57 *(.note*)
58 }
59
60 . = ASSERT(_end <= WAKEUP_SIZE, "Wakeup too big!");
61}
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index dd78326ae47c..afc25ee9964b 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -10,30 +10,72 @@
10#include <linux/dmi.h> 10#include <linux/dmi.h>
11#include <linux/cpumask.h> 11#include <linux/cpumask.h>
12 12
13#include <asm/smp.h> 13#include "realmode/wakeup.h"
14#include "sleep.h"
14 15
15/* address in low memory of the wakeup routine. */
16unsigned long acpi_wakeup_address; 16unsigned long acpi_wakeup_address;
17unsigned long acpi_realmode_flags; 17unsigned long acpi_realmode_flags;
18extern char wakeup_start, wakeup_end;
19 18
20extern unsigned long acpi_copy_wakeup_routine(unsigned long); 19/* address in low memory of the wakeup routine. */
20static unsigned long acpi_realmode;
21
22#ifdef CONFIG_64BIT
23static char temp_stack[10240];
24#endif
21 25
22/** 26/**
23 * acpi_save_state_mem - save kernel state 27 * acpi_save_state_mem - save kernel state
24 * 28 *
25 * Create an identity mapped page table and copy the wakeup routine to 29 * Create an identity mapped page table and copy the wakeup routine to
26 * low memory. 30 * low memory.
31 *
32 * Note that this is too late to change acpi_wakeup_address.
27 */ 33 */
28int acpi_save_state_mem(void) 34int acpi_save_state_mem(void)
29{ 35{
30 if (!acpi_wakeup_address) { 36 struct wakeup_header *header;
31 printk(KERN_ERR "Could not allocate memory during boot, S3 disabled\n"); 37
38 if (!acpi_realmode) {
39 printk(KERN_ERR "Could not allocate memory during boot, "
40 "S3 disabled\n");
32 return -ENOMEM; 41 return -ENOMEM;
33 } 42 }
34 memcpy((void *)acpi_wakeup_address, &wakeup_start, 43 memcpy((void *)acpi_realmode, &wakeup_code_start, WAKEUP_SIZE);
35 &wakeup_end - &wakeup_start); 44
36 acpi_copy_wakeup_routine(acpi_wakeup_address); 45 header = (struct wakeup_header *)(acpi_realmode + HEADER_OFFSET);
46 if (header->signature != 0x51ee1111) {
47 printk(KERN_ERR "wakeup header does not match\n");
48 return -EINVAL;
49 }
50
51 header->video_mode = saved_video_mode;
52
53#ifndef CONFIG_64BIT
54 store_gdt((struct desc_ptr *)&header->pmode_gdt);
55
56 header->pmode_efer_low = nx_enabled;
57 if (header->pmode_efer_low & 1) {
58 /* This is strange, why not save efer, always? */
59 rdmsr(MSR_EFER, header->pmode_efer_low,
60 header->pmode_efer_high);
61 }
62#endif /* !CONFIG_64BIT */
63
64 header->pmode_cr0 = read_cr0();
65 header->pmode_cr4 = read_cr4();
66 header->realmode_flags = acpi_realmode_flags;
67 header->real_magic = 0x12345678;
68
69#ifndef CONFIG_64BIT
70 header->pmode_entry = (u32)&wakeup_pmode_return;
71 header->pmode_cr3 = (u32)(swsusp_pg_dir - __PAGE_OFFSET);
72 saved_magic = 0x12345678;
73#else /* CONFIG_64BIT */
74 header->trampoline_segment = setup_trampoline() >> 4;
75 init_rsp = (unsigned long)temp_stack + 4096;
76 initial_code = (unsigned long)wakeup_long64;
77 saved_magic = 0x123456789abcdef0;
78#endif /* CONFIG_64BIT */
37 79
38 return 0; 80 return 0;
39} 81}
@@ -56,15 +98,20 @@ void acpi_restore_state_mem(void)
56 */ 98 */
57void __init acpi_reserve_bootmem(void) 99void __init acpi_reserve_bootmem(void)
58{ 100{
59 if ((&wakeup_end - &wakeup_start) > PAGE_SIZE*2) { 101 if ((&wakeup_code_end - &wakeup_code_start) > WAKEUP_SIZE) {
60 printk(KERN_ERR 102 printk(KERN_ERR
61 "ACPI: Wakeup code way too big, S3 disabled.\n"); 103 "ACPI: Wakeup code way too big, S3 disabled.\n");
62 return; 104 return;
63 } 105 }
64 106
65 acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE*2); 107 acpi_realmode = (unsigned long)alloc_bootmem_low(WAKEUP_SIZE);
66 if (!acpi_wakeup_address) 108
109 if (!acpi_realmode) {
67 printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n"); 110 printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n");
111 return;
112 }
113
114 acpi_wakeup_address = acpi_realmode;
68} 115}
69 116
70 117
diff --git a/arch/x86/kernel/acpi/sleep.h b/arch/x86/kernel/acpi/sleep.h
new file mode 100644
index 000000000000..adbcbaa6f1df
--- /dev/null
+++ b/arch/x86/kernel/acpi/sleep.h
@@ -0,0 +1,16 @@
1/*
2 * Variables and functions used by the code in sleep.c
3 */
4
5#include <asm/trampoline.h>
6
7extern char wakeup_code_start, wakeup_code_end;
8
9extern unsigned long saved_video_mode;
10extern long saved_magic;
11
12extern int wakeup_pmode_return;
13extern char swsusp_pg_dir[PAGE_SIZE];
14
15extern unsigned long acpi_copy_wakeup_routine(unsigned long);
16extern void wakeup_long64(void);
diff --git a/arch/x86/kernel/acpi/sleep_32.c b/arch/x86/kernel/acpi/sleep_32.c
deleted file mode 100644
index 63fe5525e026..000000000000
--- a/arch/x86/kernel/acpi/sleep_32.c
+++ /dev/null
@@ -1,40 +0,0 @@
1/*
2 * sleep.c - x86-specific ACPI sleep support.
3 *
4 * Copyright (C) 2001-2003 Patrick Mochel
5 * Copyright (C) 2001-2003 Pavel Machek <pavel@suse.cz>
6 */
7
8#include <linux/acpi.h>
9#include <linux/bootmem.h>
10#include <linux/dmi.h>
11#include <linux/cpumask.h>
12
13#include <asm/smp.h>
14
15/* Ouch, we want to delete this. We already have better version in userspace, in
16 s2ram from suspend.sf.net project */
17static __init int reset_videomode_after_s3(const struct dmi_system_id *d)
18{
19 acpi_realmode_flags |= 2;
20 return 0;
21}
22
23static __initdata struct dmi_system_id acpisleep_dmi_table[] = {
24 { /* Reset video mode after returning from ACPI S3 sleep */
25 .callback = reset_videomode_after_s3,
26 .ident = "Toshiba Satellite 4030cdt",
27 .matches = {
28 DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
29 },
30 },
31 {}
32};
33
34static int __init acpisleep_dmi_init(void)
35{
36 dmi_check_system(acpisleep_dmi_table);
37 return 0;
38}
39
40core_initcall(acpisleep_dmi_init);
diff --git a/arch/x86/kernel/acpi/wakeup_32.S b/arch/x86/kernel/acpi/wakeup_32.S
index f53e3277f8e5..a12e6a9fb659 100644
--- a/arch/x86/kernel/acpi/wakeup_32.S
+++ b/arch/x86/kernel/acpi/wakeup_32.S
@@ -3,178 +3,12 @@
3#include <asm/segment.h> 3#include <asm/segment.h>
4#include <asm/page.h> 4#include <asm/page.h>
5 5
6# 6# Copyright 2003, 2008 Pavel Machek <pavel@suse.cz>, distribute under GPLv2
7# wakeup_code runs in real mode, and at unknown address (determined at run-time).
8# Therefore it must only use relative jumps/calls.
9#
10# Do we need to deal with A20? It is okay: ACPI specs says A20 must be enabled
11#
12# If physical address of wakeup_code is 0x12345, BIOS should call us with
13# cs = 0x1234, eip = 0x05
14#
15
16#define BEEP \
17 inb $97, %al; \
18 outb %al, $0x80; \
19 movb $3, %al; \
20 outb %al, $97; \
21 outb %al, $0x80; \
22 movb $-74, %al; \
23 outb %al, $67; \
24 outb %al, $0x80; \
25 movb $-119, %al; \
26 outb %al, $66; \
27 outb %al, $0x80; \
28 movb $15, %al; \
29 outb %al, $66;
30
31ALIGN
32 .align 4096
33ENTRY(wakeup_start)
34wakeup_code:
35 wakeup_code_start = .
36 .code16
37
38 cli
39 cld
40
41 # setup data segment
42 movw %cs, %ax
43 movw %ax, %ds # Make ds:0 point to wakeup_start
44 movw %ax, %ss
45
46 testl $4, realmode_flags - wakeup_code
47 jz 1f
48 BEEP
491:
50 mov $(wakeup_stack - wakeup_code), %sp # Private stack is needed for ASUS board
51
52 pushl $0 # Kill any dangerous flags
53 popfl
54
55 movl real_magic - wakeup_code, %eax
56 cmpl $0x12345678, %eax
57 jne bogus_real_magic
58
59 testl $1, realmode_flags - wakeup_code
60 jz 1f
61 lcall $0xc000,$3
62 movw %cs, %ax
63 movw %ax, %ds # Bios might have played with that
64 movw %ax, %ss
651:
66
67 testl $2, realmode_flags - wakeup_code
68 jz 1f
69 mov video_mode - wakeup_code, %ax
70 call mode_set
711:
72
73 # set up page table
74 movl $swsusp_pg_dir-__PAGE_OFFSET, %eax
75 movl %eax, %cr3
76
77 testl $1, real_efer_save_restore - wakeup_code
78 jz 4f
79 # restore efer setting
80 movl real_save_efer_edx - wakeup_code, %edx
81 movl real_save_efer_eax - wakeup_code, %eax
82 mov $0xc0000080, %ecx
83 wrmsr
844:
85 # make sure %cr4 is set correctly (features, etc)
86 movl real_save_cr4 - wakeup_code, %eax
87 movl %eax, %cr4
88
89 # need a gdt -- use lgdtl to force 32-bit operands, in case
90 # the GDT is located past 16 megabytes.
91 lgdtl real_save_gdt - wakeup_code
92
93 movl real_save_cr0 - wakeup_code, %eax
94 movl %eax, %cr0
95 jmp 1f
961:
97 movl real_magic - wakeup_code, %eax
98 cmpl $0x12345678, %eax
99 jne bogus_real_magic
100
101 testl $8, realmode_flags - wakeup_code
102 jz 1f
103 BEEP
1041:
105 ljmpl $__KERNEL_CS, $wakeup_pmode_return
106
107real_save_gdt: .word 0
108 .long 0
109real_save_cr0: .long 0
110real_save_cr3: .long 0
111real_save_cr4: .long 0
112real_magic: .long 0
113video_mode: .long 0
114realmode_flags: .long 0
115real_efer_save_restore: .long 0
116real_save_efer_edx: .long 0
117real_save_efer_eax: .long 0
118
119bogus_real_magic:
120 jmp bogus_real_magic
121
122/* This code uses an extended set of video mode numbers. These include:
123 * Aliases for standard modes
124 * NORMAL_VGA (-1)
125 * EXTENDED_VGA (-2)
126 * ASK_VGA (-3)
127 * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
128 * of compatibility when extending the table. These are between 0x00 and 0xff.
129 */
130#define VIDEO_FIRST_MENU 0x0000
131
132/* Standard BIOS video modes (BIOS number + 0x0100) */
133#define VIDEO_FIRST_BIOS 0x0100
134
135/* VESA BIOS video modes (VESA number + 0x0200) */
136#define VIDEO_FIRST_VESA 0x0200
137
138/* Video7 special modes (BIOS number + 0x0900) */
139#define VIDEO_FIRST_V7 0x0900
140
141# Setting of user mode (AX=mode ID) => CF=success
142
143# For now, we only handle VESA modes (0x0200..0x03ff). To handle other
144# modes, we should probably compile in the video code from the boot
145# directory.
146mode_set:
147 movw %ax, %bx
148 subb $VIDEO_FIRST_VESA>>8, %bh
149 cmpb $2, %bh
150 jb check_vesa
151
152setbad:
153 clc
154 ret
155
156check_vesa:
157 orw $0x4000, %bx # Use linear frame buffer
158 movw $0x4f02, %ax # VESA BIOS mode set call
159 int $0x10
160 cmpw $0x004f, %ax # AL=4f if implemented
161 jnz setbad # AH=0 if OK
162
163 stc
164 ret
165 7
166 .code32 8 .code32
167 ALIGN 9 ALIGN
168 10
169.org 0x800 11ENTRY(wakeup_pmode_return)
170wakeup_stack_begin: # Stack grows down
171
172.org 0xff0 # Just below end of page
173wakeup_stack:
174ENTRY(wakeup_end)
175
176.org 0x1000
177
178wakeup_pmode_return: 12wakeup_pmode_return:
179 movw $__KERNEL_DS, %ax 13 movw $__KERNEL_DS, %ax
180 movw %ax, %ss 14 movw %ax, %ss
@@ -187,7 +21,7 @@ wakeup_pmode_return:
187 lgdt saved_gdt 21 lgdt saved_gdt
188 lidt saved_idt 22 lidt saved_idt
189 lldt saved_ldt 23 lldt saved_ldt
190 ljmp $(__KERNEL_CS),$1f 24 ljmp $(__KERNEL_CS), $1f
1911: 251:
192 movl %cr3, %eax 26 movl %cr3, %eax
193 movl %eax, %cr3 27 movl %eax, %cr3
@@ -201,82 +35,41 @@ wakeup_pmode_return:
201 jne bogus_magic 35 jne bogus_magic
202 36
203 # jump to place where we left off 37 # jump to place where we left off
204 movl saved_eip,%eax 38 movl saved_eip, %eax
205 jmp *%eax 39 jmp *%eax
206 40
207bogus_magic: 41bogus_magic:
208 jmp bogus_magic 42 jmp bogus_magic
209 43
210 44
211##
212# acpi_copy_wakeup_routine
213#
214# Copy the above routine to low memory.
215#
216# Parameters:
217# %eax: place to copy wakeup routine to
218#
219# Returned address is location of code in low memory (past data and stack)
220#
221ENTRY(acpi_copy_wakeup_routine)
222 45
223 pushl %ebx 46save_registers:
224 sgdt saved_gdt 47 sgdt saved_gdt
225 sidt saved_idt 48 sidt saved_idt
226 sldt saved_ldt 49 sldt saved_ldt
227 str saved_tss 50 str saved_tss
228 51
229 movl nx_enabled, %edx
230 movl %edx, real_efer_save_restore - wakeup_start (%eax)
231 testl $1, real_efer_save_restore - wakeup_start (%eax)
232 jz 2f
233 # save efer setting
234 pushl %eax
235 movl %eax, %ebx
236 mov $0xc0000080, %ecx
237 rdmsr
238 movl %edx, real_save_efer_edx - wakeup_start (%ebx)
239 movl %eax, real_save_efer_eax - wakeup_start (%ebx)
240 popl %eax
2412:
242
243 movl %cr3, %edx
244 movl %edx, real_save_cr3 - wakeup_start (%eax)
245 movl %cr4, %edx
246 movl %edx, real_save_cr4 - wakeup_start (%eax)
247 movl %cr0, %edx
248 movl %edx, real_save_cr0 - wakeup_start (%eax)
249 sgdt real_save_gdt - wakeup_start (%eax)
250
251 movl saved_videomode, %edx
252 movl %edx, video_mode - wakeup_start (%eax)
253 movl acpi_realmode_flags, %edx
254 movl %edx, realmode_flags - wakeup_start (%eax)
255 movl $0x12345678, real_magic - wakeup_start (%eax)
256 movl $0x12345678, saved_magic
257 popl %ebx
258 ret
259
260save_registers:
261 leal 4(%esp), %eax 52 leal 4(%esp), %eax
262 movl %eax, saved_context_esp 53 movl %eax, saved_context_esp
263 movl %ebx, saved_context_ebx 54 movl %ebx, saved_context_ebx
264 movl %ebp, saved_context_ebp 55 movl %ebp, saved_context_ebp
265 movl %esi, saved_context_esi 56 movl %esi, saved_context_esi
266 movl %edi, saved_context_edi 57 movl %edi, saved_context_edi
267 pushfl ; popl saved_context_eflags 58 pushfl
268 59 popl saved_context_eflags
269 movl $ret_point, saved_eip 60
61 movl $ret_point, saved_eip
270 ret 62 ret
271 63
272 64
273restore_registers: 65restore_registers:
274 movl saved_context_ebp, %ebp 66 movl saved_context_ebp, %ebp
275 movl saved_context_ebx, %ebx 67 movl saved_context_ebx, %ebx
276 movl saved_context_esi, %esi 68 movl saved_context_esi, %esi
277 movl saved_context_edi, %edi 69 movl saved_context_edi, %edi
278 pushl saved_context_eflags ; popfl 70 pushl saved_context_eflags
279 ret 71 popfl
72 ret
280 73
281ENTRY(do_suspend_lowlevel) 74ENTRY(do_suspend_lowlevel)
282 call save_processor_state 75 call save_processor_state
diff --git a/arch/x86/kernel/acpi/wakeup_64.S b/arch/x86/kernel/acpi/wakeup_64.S
index 2e1b9e0d0767..bcc293423a70 100644
--- a/arch/x86/kernel/acpi/wakeup_64.S
+++ b/arch/x86/kernel/acpi/wakeup_64.S
@@ -7,191 +7,18 @@
7#include <asm/asm-offsets.h> 7#include <asm/asm-offsets.h>
8 8
9# Copyright 2003 Pavel Machek <pavel@suse.cz>, distribute under GPLv2 9# Copyright 2003 Pavel Machek <pavel@suse.cz>, distribute under GPLv2
10#
11# wakeup_code runs in real mode, and at unknown address (determined at run-time).
12# Therefore it must only use relative jumps/calls.
13#
14# Do we need to deal with A20? It is okay: ACPI specs says A20 must be enabled
15#
16# If physical address of wakeup_code is 0x12345, BIOS should call us with
17# cs = 0x1234, eip = 0x05
18#
19
20#define BEEP \
21 inb $97, %al; \
22 outb %al, $0x80; \
23 movb $3, %al; \
24 outb %al, $97; \
25 outb %al, $0x80; \
26 movb $-74, %al; \
27 outb %al, $67; \
28 outb %al, $0x80; \
29 movb $-119, %al; \
30 outb %al, $66; \
31 outb %al, $0x80; \
32 movb $15, %al; \
33 outb %al, $66;
34
35
36ALIGN
37 .align 16
38ENTRY(wakeup_start)
39wakeup_code:
40 wakeup_code_start = .
41 .code16
42
43# Running in *copy* of this code, somewhere in low 1MB.
44
45 cli
46 cld
47 # setup data segment
48 movw %cs, %ax
49 movw %ax, %ds # Make ds:0 point to wakeup_start
50 movw %ax, %ss
51
52 # Data segment must be set up before we can see whether to beep.
53 testl $4, realmode_flags - wakeup_code
54 jz 1f
55 BEEP
561:
57
58 # Private stack is needed for ASUS board
59 mov $(wakeup_stack - wakeup_code), %sp
60
61 pushl $0 # Kill any dangerous flags
62 popfl
63
64 movl real_magic - wakeup_code, %eax
65 cmpl $0x12345678, %eax
66 jne bogus_real_magic
67
68 testl $1, realmode_flags - wakeup_code
69 jz 1f
70 lcall $0xc000,$3
71 movw %cs, %ax
72 movw %ax, %ds # Bios might have played with that
73 movw %ax, %ss
741:
75
76 testl $2, realmode_flags - wakeup_code
77 jz 1f
78 mov video_mode - wakeup_code, %ax
79 call mode_set
801:
81
82 mov %ds, %ax # Find 32bit wakeup_code addr
83 movzx %ax, %esi # (Convert %ds:gdt to a liner ptr)
84 shll $4, %esi
85 # Fix up the vectors
86 addl %esi, wakeup_32_vector - wakeup_code
87 addl %esi, wakeup_long64_vector - wakeup_code
88 addl %esi, gdt_48a + 2 - wakeup_code # Fixup the gdt pointer
89
90 lidtl %ds:idt_48a - wakeup_code
91 lgdtl %ds:gdt_48a - wakeup_code # load gdt with whatever is
92 # appropriate
93
94 movl $1, %eax # protected mode (PE) bit
95 lmsw %ax # This is it!
96 jmp 1f
971:
98
99 ljmpl *(wakeup_32_vector - wakeup_code)
100
101 .balign 4
102wakeup_32_vector:
103 .long wakeup_32 - wakeup_code
104 .word __KERNEL32_CS, 0
105
106 .code32
107wakeup_32:
108# Running in this code, but at low address; paging is not yet turned on.
109
110 movl $__KERNEL_DS, %eax
111 movl %eax, %ds
112
113 /*
114 * Prepare for entering 64bits mode
115 */
116
117 /* Enable PAE */
118 xorl %eax, %eax
119 btsl $5, %eax
120 movl %eax, %cr4
121
122 /* Setup early boot stage 4 level pagetables */
123 leal (wakeup_level4_pgt - wakeup_code)(%esi), %eax
124 movl %eax, %cr3
125
126 /* Check if nx is implemented */
127 movl $0x80000001, %eax
128 cpuid
129 movl %edx,%edi
130
131 /* Enable Long Mode */
132 xorl %eax, %eax
133 btsl $_EFER_LME, %eax
134
135 /* No Execute supported? */
136 btl $20,%edi
137 jnc 1f
138 btsl $_EFER_NX, %eax
139
140 /* Make changes effective */
1411: movl $MSR_EFER, %ecx
142 xorl %edx, %edx
143 wrmsr
144
145 xorl %eax, %eax
146 btsl $31, %eax /* Enable paging and in turn activate Long Mode */
147 btsl $0, %eax /* Enable protected mode */
148
149 /* Make changes effective */
150 movl %eax, %cr0
151
152 /* At this point:
153 CR4.PAE must be 1
154 CS.L must be 0
155 CR3 must point to PML4
156 Next instruction must be a branch
157 This must be on identity-mapped page
158 */
159 /*
160 * At this point we're in long mode but in 32bit compatibility mode
161 * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
162 * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we load
163 * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
164 */
165
166 /* Finally jump in 64bit mode */
167 ljmp *(wakeup_long64_vector - wakeup_code)(%esi)
168
169 .balign 4
170wakeup_long64_vector:
171 .long wakeup_long64 - wakeup_code
172 .word __KERNEL_CS, 0
173 10
174.code64 11.code64
175
176 /* Hooray, we are in Long 64-bit mode (but still running in
177 * low memory)
178 */
179wakeup_long64:
180 /* 12 /*
181 * We must switch to a new descriptor in kernel space for the GDT 13 * Hooray, we are in Long 64-bit mode (but still running in low memory)
182 * because soon the kernel won't have access anymore to the userspace
183 * addresses where we're currently running on. We have to do that here
184 * because in 32bit we couldn't load a 64bit linear address.
185 */ 14 */
186 lgdt cpu_gdt_descr 15ENTRY(wakeup_long64)
187 16wakeup_long64:
188 movq saved_magic, %rax 17 movq saved_magic, %rax
189 movq $0x123456789abcdef0, %rdx 18 movq $0x123456789abcdef0, %rdx
190 cmpq %rdx, %rax 19 cmpq %rdx, %rax
191 jne bogus_64_magic 20 jne bogus_64_magic
192 21
193 nop
194 nop
195 movw $__KERNEL_DS, %ax 22 movw $__KERNEL_DS, %ax
196 movw %ax, %ss 23 movw %ax, %ss
197 movw %ax, %ds 24 movw %ax, %ds
@@ -208,130 +35,8 @@ wakeup_long64:
208 movq saved_rip, %rax 35 movq saved_rip, %rax
209 jmp *%rax 36 jmp *%rax
210 37
211.code32
212
213 .align 64
214gdta:
215 /* Its good to keep gdt in sync with one in trampoline.S */
216 .word 0, 0, 0, 0 # dummy
217 /* ??? Why I need the accessed bit set in order for this to work? */
218 .quad 0x00cf9b000000ffff # __KERNEL32_CS
219 .quad 0x00af9b000000ffff # __KERNEL_CS
220 .quad 0x00cf93000000ffff # __KERNEL_DS
221
222idt_48a:
223 .word 0 # idt limit = 0
224 .word 0, 0 # idt base = 0L
225
226gdt_48a:
227 .word 0x800 # gdt limit=2048,
228 # 256 GDT entries
229 .long gdta - wakeup_code # gdt base (relocated in later)
230
231real_magic: .quad 0
232video_mode: .quad 0
233realmode_flags: .quad 0
234
235.code16
236bogus_real_magic:
237 jmp bogus_real_magic
238
239.code64
240bogus_64_magic: 38bogus_64_magic:
241 jmp bogus_64_magic 39 jmp bogus_64_magic
242
243/* This code uses an extended set of video mode numbers. These include:
244 * Aliases for standard modes
245 * NORMAL_VGA (-1)
246 * EXTENDED_VGA (-2)
247 * ASK_VGA (-3)
248 * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
249 * of compatibility when extending the table. These are between 0x00 and 0xff.
250 */
251#define VIDEO_FIRST_MENU 0x0000
252
253/* Standard BIOS video modes (BIOS number + 0x0100) */
254#define VIDEO_FIRST_BIOS 0x0100
255
256/* VESA BIOS video modes (VESA number + 0x0200) */
257#define VIDEO_FIRST_VESA 0x0200
258
259/* Video7 special modes (BIOS number + 0x0900) */
260#define VIDEO_FIRST_V7 0x0900
261
262# Setting of user mode (AX=mode ID) => CF=success
263
264# For now, we only handle VESA modes (0x0200..0x03ff). To handle other
265# modes, we should probably compile in the video code from the boot
266# directory.
267.code16
268mode_set:
269 movw %ax, %bx
270 subb $VIDEO_FIRST_VESA>>8, %bh
271 cmpb $2, %bh
272 jb check_vesa
273
274setbad:
275 clc
276 ret
277
278check_vesa:
279 orw $0x4000, %bx # Use linear frame buffer
280 movw $0x4f02, %ax # VESA BIOS mode set call
281 int $0x10
282 cmpw $0x004f, %ax # AL=4f if implemented
283 jnz setbad # AH=0 if OK
284
285 stc
286 ret
287
288wakeup_stack_begin: # Stack grows down
289
290.org 0xff0
291wakeup_stack: # Just below end of page
292
293.org 0x1000
294ENTRY(wakeup_level4_pgt)
295 .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
296 .fill 510,8,0
297 /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
298 .quad level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
299
300ENTRY(wakeup_end)
301
302##
303# acpi_copy_wakeup_routine
304#
305# Copy the above routine to low memory.
306#
307# Parameters:
308# %rdi: place to copy wakeup routine to
309#
310# Returned address is location of code in low memory (past data and stack)
311#
312 .code64
313ENTRY(acpi_copy_wakeup_routine)
314 pushq %rax
315 pushq %rdx
316
317 movl saved_video_mode, %edx
318 movl %edx, video_mode - wakeup_start (,%rdi)
319 movl acpi_realmode_flags, %edx
320 movl %edx, realmode_flags - wakeup_start (,%rdi)
321 movq $0x12345678, real_magic - wakeup_start (,%rdi)
322 movq $0x123456789abcdef0, %rdx
323 movq %rdx, saved_magic
324
325 movq saved_magic, %rax
326 movq $0x123456789abcdef0, %rdx
327 cmpq %rdx, %rax
328 jne bogus_64_magic
329
330 # restore the regs we used
331 popq %rdx
332 popq %rax
333ENTRY(do_suspend_lowlevel_s4bios)
334 ret
335 40
336 .align 2 41 .align 2
337 .p2align 4,,15 42 .p2align 4,,15
@@ -414,7 +119,7 @@ do_suspend_lowlevel:
414 jmp restore_processor_state 119 jmp restore_processor_state
415.LFE5: 120.LFE5:
416.Lfe5: 121.Lfe5:
417 .size do_suspend_lowlevel,.Lfe5-do_suspend_lowlevel 122 .size do_suspend_lowlevel, .Lfe5-do_suspend_lowlevel
418 123
419.data 124.data
420ALIGN 125ALIGN
diff --git a/arch/x86/kernel/acpi/wakeup_rm.S b/arch/x86/kernel/acpi/wakeup_rm.S
new file mode 100644
index 000000000000..6ff3b5730575
--- /dev/null
+++ b/arch/x86/kernel/acpi/wakeup_rm.S
@@ -0,0 +1,10 @@
1/*
2 * Wrapper script for the realmode binary as a transport object
3 * before copying to low memory.
4 */
5 .section ".rodata","a"
6 .globl wakeup_code_start, wakeup_code_end
7wakeup_code_start:
8 .incbin "arch/x86/kernel/acpi/realmode/wakeup.bin"
9wakeup_code_end:
10 .size wakeup_code_start, .-wakeup_code_start
diff --git a/arch/x86/kernel/e820_64.c b/arch/x86/kernel/e820_64.c
index a720f3d5ed9d..7f6c0c85c8f6 100644
--- a/arch/x86/kernel/e820_64.c
+++ b/arch/x86/kernel/e820_64.c
@@ -27,6 +27,7 @@
27#include <asm/setup.h> 27#include <asm/setup.h>
28#include <asm/sections.h> 28#include <asm/sections.h>
29#include <asm/kdebug.h> 29#include <asm/kdebug.h>
30#include <asm/trampoline.h>
30 31
31struct e820map e820; 32struct e820map e820;
32 33
@@ -58,8 +59,8 @@ struct early_res {
58}; 59};
59static struct early_res early_res[MAX_EARLY_RES] __initdata = { 60static struct early_res early_res[MAX_EARLY_RES] __initdata = {
60 { 0, PAGE_SIZE, "BIOS data page" }, /* BIOS data page */ 61 { 0, PAGE_SIZE, "BIOS data page" }, /* BIOS data page */
61#ifdef CONFIG_SMP 62#ifdef CONFIG_X86_TRAMPOLINE
62 { SMP_TRAMPOLINE_BASE, SMP_TRAMPOLINE_BASE + 2*PAGE_SIZE, "SMP_TRAMPOLINE" }, 63 { TRAMPOLINE_BASE, TRAMPOLINE_BASE + 2 * PAGE_SIZE, "TRAMPOLINE" },
63#endif 64#endif
64 {} 65 {}
65}; 66};
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index c1d7a877d814..10a1955bb1d1 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -132,10 +132,6 @@ ident_complete:
132 addq %rbp, trampoline_level4_pgt + 0(%rip) 132 addq %rbp, trampoline_level4_pgt + 0(%rip)
133 addq %rbp, trampoline_level4_pgt + (511*8)(%rip) 133 addq %rbp, trampoline_level4_pgt + (511*8)(%rip)
134#endif 134#endif
135#ifdef CONFIG_ACPI_SLEEP
136 addq %rbp, wakeup_level4_pgt + 0(%rip)
137 addq %rbp, wakeup_level4_pgt + (511*8)(%rip)
138#endif
139 135
140 /* Due to ENTRY(), sometimes the empty space gets filled with 136 /* Due to ENTRY(), sometimes the empty space gets filled with
141 * zeros. Better take a jmp than relying on empty space being 137 * zeros. Better take a jmp than relying on empty space being
diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c
index 4b198d9d0de3..5b0bffb7fcc9 100644
--- a/arch/x86/kernel/setup_32.c
+++ b/arch/x86/kernel/setup_32.c
@@ -192,7 +192,7 @@ EXPORT_SYMBOL(ist_info);
192extern void early_cpu_init(void); 192extern void early_cpu_init(void);
193extern int root_mountflags; 193extern int root_mountflags;
194 194
195unsigned long saved_videomode; 195unsigned long saved_video_mode;
196 196
197#define RAMDISK_IMAGE_START_MASK 0x07FF 197#define RAMDISK_IMAGE_START_MASK 0x07FF
198#define RAMDISK_PROMPT_FLAG 0x8000 198#define RAMDISK_PROMPT_FLAG 0x8000
@@ -763,7 +763,7 @@ void __init setup_arch(char **cmdline_p)
763 edid_info = boot_params.edid_info; 763 edid_info = boot_params.edid_info;
764 apm_info.bios = boot_params.apm_bios_info; 764 apm_info.bios = boot_params.apm_bios_info;
765 ist_info = boot_params.ist_info; 765 ist_info = boot_params.ist_info;
766 saved_videomode = boot_params.hdr.vid_mode; 766 saved_video_mode = boot_params.hdr.vid_mode;
767 if( boot_params.sys_desc_table.length != 0 ) { 767 if( boot_params.sys_desc_table.length != 0 ) {
768 set_mca_bus(boot_params.sys_desc_table.table[3] & 0x2); 768 set_mca_bus(boot_params.sys_desc_table.table[3] & 0x2);
769 machine_id = boot_params.sys_desc_table.table[0]; 769 machine_id = boot_params.sys_desc_table.table[0];
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index b80300710c08..674ef3510cdf 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -65,6 +65,7 @@
65#include <asm/mce.h> 65#include <asm/mce.h>
66#include <asm/ds.h> 66#include <asm/ds.h>
67#include <asm/topology.h> 67#include <asm/topology.h>
68#include <asm/trampoline.h>
68 69
69#include <mach_apic.h> 70#include <mach_apic.h>
70#ifdef CONFIG_PARAVIRT 71#ifdef CONFIG_PARAVIRT
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index ca3929b16049..424600e671bd 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -53,6 +53,7 @@
53#include <asm/nmi.h> 53#include <asm/nmi.h>
54#include <asm/irq.h> 54#include <asm/irq.h>
55#include <asm/smp.h> 55#include <asm/smp.h>
56#include <asm/trampoline.h>
56#include <asm/cpu.h> 57#include <asm/cpu.h>
57#include <asm/numa.h> 58#include <asm/numa.h>
58#include <asm/pgtable.h> 59#include <asm/pgtable.h>
@@ -140,7 +141,7 @@ static atomic_t init_deasserted;
140static int boot_cpu_logical_apicid; 141static int boot_cpu_logical_apicid;
141 142
142/* ready for x86_64, no harm for x86, since it will overwrite after alloc */ 143/* ready for x86_64, no harm for x86, since it will overwrite after alloc */
143unsigned char *trampoline_base = __va(SMP_TRAMPOLINE_BASE); 144unsigned char *trampoline_base = __va(TRAMPOLINE_BASE);
144 145
145/* representing cpus for which sibling maps can be computed */ 146/* representing cpus for which sibling maps can be computed */
146static cpumask_t cpu_sibling_setup_map; 147static cpumask_t cpu_sibling_setup_map;
@@ -554,8 +555,7 @@ cpumask_t cpu_coregroup_map(int cpu)
554 * bootstrap into the page concerned. The caller 555 * bootstrap into the page concerned. The caller
555 * has made sure it's suitably aligned. 556 * has made sure it's suitably aligned.
556 */ 557 */
557 558unsigned long setup_trampoline(void)
558unsigned long __cpuinit setup_trampoline(void)
559{ 559{
560 memcpy(trampoline_base, trampoline_data, 560 memcpy(trampoline_base, trampoline_data,
561 trampoline_end - trampoline_data); 561 trampoline_end - trampoline_data);
diff --git a/arch/x86/kernel/trampoline_64.S b/arch/x86/kernel/trampoline_64.S
index 2a07e67d6697..894293c598db 100644
--- a/arch/x86/kernel/trampoline_64.S
+++ b/arch/x86/kernel/trampoline_64.S
@@ -30,12 +30,7 @@
30#include <asm/msr.h> 30#include <asm/msr.h>
31#include <asm/segment.h> 31#include <asm/segment.h>
32 32
33/* We can free up trampoline after bootup if cpu hotplug is not supported. */
34#ifndef CONFIG_HOTPLUG_CPU
35.section .cpuinit.data, "aw", @progbits
36#else
37.section .rodata, "a", @progbits 33.section .rodata, "a", @progbits
38#endif
39 34
40.code16 35.code16
41 36
diff --git a/arch/x86/mach-voyager/voyager_smp.c b/arch/x86/mach-voyager/voyager_smp.c
index 4397235c2e30..be7235bf105d 100644
--- a/arch/x86/mach-voyager/voyager_smp.c
+++ b/arch/x86/mach-voyager/voyager_smp.c
@@ -27,6 +27,7 @@
27#include <asm/pgalloc.h> 27#include <asm/pgalloc.h>
28#include <asm/tlbflush.h> 28#include <asm/tlbflush.h>
29#include <asm/arch_hooks.h> 29#include <asm/arch_hooks.h>
30#include <asm/trampoline.h>
30 31
31/* TLB state -- visible externally, indexed physically */ 32/* TLB state -- visible externally, indexed physically */
32DEFINE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate) = { &init_mm, 0 }; 33DEFINE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate) = { &init_mm, 0 };
diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h
index 3496e1c299b2..62ebdec394b9 100644
--- a/include/asm-x86/smp.h
+++ b/include/asm-x86/smp.h
@@ -45,22 +45,12 @@ DECLARE_PER_CPU(u16, cpu_llc_id);
45DECLARE_PER_CPU(u16, x86_cpu_to_apicid); 45DECLARE_PER_CPU(u16, x86_cpu_to_apicid);
46DECLARE_PER_CPU(u16, x86_bios_cpu_apicid); 46DECLARE_PER_CPU(u16, x86_bios_cpu_apicid);
47 47
48/*
49 * Trampoline 80x86 program as an array.
50 */
51extern const unsigned char trampoline_data [];
52extern const unsigned char trampoline_end [];
53extern unsigned char *trampoline_base;
54
55/* Static state in head.S used to set up a CPU */ 48/* Static state in head.S used to set up a CPU */
56extern struct { 49extern struct {
57 void *sp; 50 void *sp;
58 unsigned short ss; 51 unsigned short ss;
59} stack_start; 52} stack_start;
60 53
61extern unsigned long init_rsp;
62extern unsigned long initial_code;
63
64struct smp_ops { 54struct smp_ops {
65 void (*smp_prepare_boot_cpu)(void); 55 void (*smp_prepare_boot_cpu)(void);
66 void (*smp_prepare_cpus)(unsigned max_cpus); 56 void (*smp_prepare_cpus)(unsigned max_cpus);
@@ -130,9 +120,6 @@ extern void __cpu_die(unsigned int cpu);
130 120
131extern void prefill_possible_map(void); 121extern void prefill_possible_map(void);
132 122
133#define SMP_TRAMPOLINE_BASE 0x6000
134extern unsigned long setup_trampoline(void);
135
136void smp_store_cpu_info(int id); 123void smp_store_cpu_info(int id);
137#define cpu_physical_id(cpu) per_cpu(x86_cpu_to_apicid, cpu) 124#define cpu_physical_id(cpu) per_cpu(x86_cpu_to_apicid, cpu)
138 125
diff --git a/include/asm-x86/trampoline.h b/include/asm-x86/trampoline.h
new file mode 100644
index 000000000000..b156b08d0131
--- /dev/null
+++ b/include/asm-x86/trampoline.h
@@ -0,0 +1,21 @@
1#ifndef __TRAMPOLINE_HEADER
2#define __TRAMPOLINE_HEADER
3
4#ifndef __ASSEMBLY__
5
6/*
7 * Trampoline 80x86 program as an array.
8 */
9extern const unsigned char trampoline_data [];
10extern const unsigned char trampoline_end [];
11extern unsigned char *trampoline_base;
12
13extern unsigned long init_rsp;
14extern unsigned long initial_code;
15
16#define TRAMPOLINE_BASE 0x6000
17extern unsigned long setup_trampoline(void);
18
19#endif /* __ASSEMBLY__ */
20
21#endif /* __TRAMPOLINE_HEADER */