aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/acpi/sleep.c
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 /arch/x86/kernel/acpi/sleep.c
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>
Diffstat (limited to 'arch/x86/kernel/acpi/sleep.c')
-rw-r--r--arch/x86/kernel/acpi/sleep.c71
1 files changed, 59 insertions, 12 deletions
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