0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/acpi.h>
0010 #include <linux/memblock.h>
0011 #include <linux/dmi.h>
0012 #include <linux/cpumask.h>
0013 #include <linux/pgtable.h>
0014 #include <asm/segment.h>
0015 #include <asm/desc.h>
0016 #include <asm/cacheflush.h>
0017 #include <asm/realmode.h>
0018 #include <asm/hypervisor.h>
0019
0020 #include <linux/ftrace.h>
0021 #include "../../realmode/rm/wakeup.h"
0022 #include "sleep.h"
0023
0024 unsigned long acpi_realmode_flags;
0025
0026 #if defined(CONFIG_SMP) && defined(CONFIG_64BIT)
0027 static char temp_stack[4096];
0028 #endif
0029
0030
0031
0032
0033
0034
0035
0036 unsigned long acpi_get_wakeup_address(void)
0037 {
0038 return ((unsigned long)(real_mode_header->wakeup_start));
0039 }
0040
0041
0042
0043
0044
0045
0046
0047 asmlinkage acpi_status __visible x86_acpi_enter_sleep_state(u8 state)
0048 {
0049 return acpi_enter_sleep_state(state);
0050 }
0051
0052
0053
0054
0055
0056
0057
0058 int x86_acpi_suspend_lowlevel(void)
0059 {
0060 struct wakeup_header *header =
0061 (struct wakeup_header *) __va(real_mode_header->wakeup_header);
0062
0063 if (header->signature != WAKEUP_HEADER_SIGNATURE) {
0064 printk(KERN_ERR "wakeup header does not match\n");
0065 return -EINVAL;
0066 }
0067
0068 header->video_mode = saved_video_mode;
0069
0070 header->pmode_behavior = 0;
0071
0072 #ifndef CONFIG_64BIT
0073 native_store_gdt((struct desc_ptr *)&header->pmode_gdt);
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083 if (!rdmsr_safe(MSR_EFER,
0084 &header->pmode_efer_low,
0085 &header->pmode_efer_high) &&
0086 !wrmsr_safe(MSR_EFER,
0087 header->pmode_efer_low,
0088 header->pmode_efer_high))
0089 header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_EFER);
0090 #endif
0091
0092 header->pmode_cr0 = read_cr0();
0093 if (__this_cpu_read(cpu_info.cpuid_level) >= 0) {
0094 header->pmode_cr4 = __read_cr4();
0095 header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_CR4);
0096 }
0097 if (!rdmsr_safe(MSR_IA32_MISC_ENABLE,
0098 &header->pmode_misc_en_low,
0099 &header->pmode_misc_en_high) &&
0100 !wrmsr_safe(MSR_IA32_MISC_ENABLE,
0101 header->pmode_misc_en_low,
0102 header->pmode_misc_en_high))
0103 header->pmode_behavior |=
0104 (1 << WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE);
0105 header->realmode_flags = acpi_realmode_flags;
0106 header->real_magic = 0x12345678;
0107
0108 #ifndef CONFIG_64BIT
0109 header->pmode_entry = (u32)&wakeup_pmode_return;
0110 header->pmode_cr3 = (u32)__pa_symbol(initial_page_table);
0111 saved_magic = 0x12345678;
0112 #else
0113 #ifdef CONFIG_SMP
0114 initial_stack = (unsigned long)temp_stack + sizeof(temp_stack);
0115 early_gdt_descr.address =
0116 (unsigned long)get_cpu_gdt_rw(smp_processor_id());
0117 initial_gs = per_cpu_offset(smp_processor_id());
0118 #endif
0119 initial_code = (unsigned long)wakeup_long64;
0120 saved_magic = 0x123456789abcdef0L;
0121 #endif
0122
0123
0124
0125
0126
0127 pause_graph_tracing();
0128 do_suspend_lowlevel();
0129 unpause_graph_tracing();
0130 return 0;
0131 }
0132
0133 static int __init acpi_sleep_setup(char *str)
0134 {
0135 while ((str != NULL) && (*str != '\0')) {
0136 if (strncmp(str, "s3_bios", 7) == 0)
0137 acpi_realmode_flags |= 1;
0138 if (strncmp(str, "s3_mode", 7) == 0)
0139 acpi_realmode_flags |= 2;
0140 if (strncmp(str, "s3_beep", 7) == 0)
0141 acpi_realmode_flags |= 4;
0142 #ifdef CONFIG_HIBERNATION
0143 if (strncmp(str, "s4_hwsig", 8) == 0)
0144 acpi_check_s4_hw_signature = 1;
0145 if (strncmp(str, "s4_nohwsig", 10) == 0)
0146 acpi_check_s4_hw_signature = 0;
0147 #endif
0148 if (strncmp(str, "nonvs", 5) == 0)
0149 acpi_nvs_nosave();
0150 if (strncmp(str, "nonvs_s3", 8) == 0)
0151 acpi_nvs_nosave_s3();
0152 if (strncmp(str, "old_ordering", 12) == 0)
0153 acpi_old_suspend_ordering();
0154 if (strncmp(str, "nobl", 4) == 0)
0155 acpi_sleep_no_blacklist();
0156 str = strchr(str, ',');
0157 if (str != NULL)
0158 str += strspn(str, ", \t");
0159 }
0160 return 1;
0161 }
0162
0163 __setup("acpi_sleep=", acpi_sleep_setup);
0164
0165 #if defined(CONFIG_HIBERNATION) && defined(CONFIG_HYPERVISOR_GUEST)
0166 static int __init init_s4_sigcheck(void)
0167 {
0168
0169
0170
0171
0172
0173 if (acpi_check_s4_hw_signature == -1 &&
0174 !hypervisor_is_type(X86_HYPER_NATIVE))
0175 acpi_check_s4_hw_signature = 1;
0176
0177 return 0;
0178 }
0179
0180 arch_initcall(init_s4_sigcheck);
0181 #endif