^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * sleep.c - x86-specific ACPI sleep support.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2001-2003 Patrick Mochel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2001-2003 Pavel Machek <pavel@ucw.cz>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/memblock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/dmi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/cpumask.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/pgtable.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/segment.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/desc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/cacheflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/realmode.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/ftrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include "../../realmode/rm/wakeup.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include "sleep.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) unsigned long acpi_realmode_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #if defined(CONFIG_SMP) && defined(CONFIG_64BIT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static char temp_stack[4096];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * acpi_get_wakeup_address - provide physical address for S3 wakeup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * Returns the physical address where the kernel should be resumed after the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * system awakes from S3, e.g. for programming into the firmware waking vector.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) unsigned long acpi_get_wakeup_address(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return ((unsigned long)(real_mode_header->wakeup_start));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * x86_acpi_enter_sleep_state - enter sleep state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * @state: Sleep state to enter.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * Wrapper around acpi_enter_sleep_state() to be called by assmebly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) asmlinkage acpi_status __visible x86_acpi_enter_sleep_state(u8 state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) return acpi_enter_sleep_state(state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * x86_acpi_suspend_lowlevel - save kernel state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * Create an identity mapped page table and copy the wakeup routine to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * low memory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) int x86_acpi_suspend_lowlevel(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct wakeup_header *header =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) (struct wakeup_header *) __va(real_mode_header->wakeup_header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (header->signature != WAKEUP_HEADER_SIGNATURE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) printk(KERN_ERR "wakeup header does not match\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) header->video_mode = saved_video_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) header->pmode_behavior = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #ifndef CONFIG_64BIT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) native_store_gdt((struct desc_ptr *)&header->pmode_gdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * We have to check that we can write back the value, and not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * just read it. At least on 90 nm Pentium M (Family 6, Model
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * 13), reading an invalid MSR is not guaranteed to trap, see
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * Erratum X4 in "Intel Pentium M Processor on 90 nm Process
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * with 2-MB L2 Cache and Intel® Processor A100 and A110 on 90
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * nm process with 512-KB L2 Cache Specification Update".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (!rdmsr_safe(MSR_EFER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) &header->pmode_efer_low,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) &header->pmode_efer_high) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) !wrmsr_safe(MSR_EFER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) header->pmode_efer_low,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) header->pmode_efer_high))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_EFER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #endif /* !CONFIG_64BIT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) header->pmode_cr0 = read_cr0();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (__this_cpu_read(cpu_info.cpuid_level) >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) header->pmode_cr4 = __read_cr4();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_CR4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (!rdmsr_safe(MSR_IA32_MISC_ENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) &header->pmode_misc_en_low,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) &header->pmode_misc_en_high) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) !wrmsr_safe(MSR_IA32_MISC_ENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) header->pmode_misc_en_low,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) header->pmode_misc_en_high))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) header->pmode_behavior |=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) (1 << WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) header->realmode_flags = acpi_realmode_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) header->real_magic = 0x12345678;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) #ifndef CONFIG_64BIT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) header->pmode_entry = (u32)&wakeup_pmode_return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) header->pmode_cr3 = (u32)__pa_symbol(initial_page_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) saved_magic = 0x12345678;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) #else /* CONFIG_64BIT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) #ifdef CONFIG_SMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) initial_stack = (unsigned long)temp_stack + sizeof(temp_stack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) early_gdt_descr.address =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) (unsigned long)get_cpu_gdt_rw(smp_processor_id());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) initial_gs = per_cpu_offset(smp_processor_id());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) initial_code = (unsigned long)wakeup_long64;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) saved_magic = 0x123456789abcdef0L;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) #endif /* CONFIG_64BIT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * Pause/unpause graph tracing around do_suspend_lowlevel as it has
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) * inconsistent call/return info after it jumps to the wakeup vector.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) pause_graph_tracing();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) do_suspend_lowlevel();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) unpause_graph_tracing();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static int __init acpi_sleep_setup(char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) while ((str != NULL) && (*str != '\0')) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (strncmp(str, "s3_bios", 7) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) acpi_realmode_flags |= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (strncmp(str, "s3_mode", 7) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) acpi_realmode_flags |= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (strncmp(str, "s3_beep", 7) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) acpi_realmode_flags |= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) #ifdef CONFIG_HIBERNATION
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (strncmp(str, "s4_nohwsig", 10) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) acpi_no_s4_hw_signature();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (strncmp(str, "nonvs", 5) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) acpi_nvs_nosave();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (strncmp(str, "nonvs_s3", 8) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) acpi_nvs_nosave_s3();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (strncmp(str, "old_ordering", 12) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) acpi_old_suspend_ordering();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (strncmp(str, "nobl", 4) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) acpi_sleep_no_blacklist();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) str = strchr(str, ',');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (str != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) str += strspn(str, ", \t");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) __setup("acpi_sleep=", acpi_sleep_setup);