1 /* $NetBSD: acpi_wakeup.c,v 1.53 2020/05/21 21:12:30 ad Exp $ */ 2 3 /*- 4 * Copyright (c) 2002, 2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Takuya SHIOZAKI. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /*- 33 * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org> 34 * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> 35 * All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 46 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 56 * SUCH DAMAGE. 57 * 58 * FreeBSD: src/sys/i386/acpica/acpi_wakeup.c,v 1.9 2002/01/10 03:26:46 wes Exp 59 */ 60 61 #include <sys/cdefs.h> 62 __KERNEL_RCSID(0, "$NetBSD: acpi_wakeup.c,v 1.53 2020/05/21 21:12:30 ad Exp $"); 63 64 #include <sys/param.h> 65 #include <sys/systm.h> 66 #include <sys/kernel.h> 67 #include <sys/bus.h> 68 #include <sys/cpu.h> 69 #include <sys/kcpuset.h> 70 #include <sys/sysctl.h> 71 72 #include <uvm/uvm_extern.h> 73 74 #ifdef __i386__ 75 #include "opt_mtrr.h" 76 #endif 77 #include "ioapic.h" 78 #include "lapic.h" 79 80 #if NLAPIC > 0 81 #include <machine/i82489var.h> 82 #endif 83 #if NIOAPIC > 0 84 #include <machine/i82093var.h> 85 #endif 86 #include <machine/i8259.h> 87 88 #include "acpica.h" 89 90 #include <dev/ic/i8253reg.h> 91 #include <dev/acpi/acpica.h> 92 #include <dev/acpi/acpivar.h> 93 #define ACPI_MACHDEP_PRIVATE 94 #include <machine/acpi_machdep.h> 95 #include <machine/cpu.h> 96 #include <machine/mtrr.h> 97 98 #include <x86/cpuvar.h> 99 #include <x86/x86/tsc.h> 100 #include <x86/fpu.h> 101 102 #include "opt_vga.h" 103 104 #include "acpi_wakecode.h" 105 106 /* Address is also hard-coded in acpi_wakecode.S */ 107 static paddr_t acpi_wakeup_paddr = 3 * PAGE_SIZE; 108 static vaddr_t acpi_wakeup_vaddr; 109 110 int acpi_md_vbios_reset = 0; /* Referenced by dev/pci/vga_pci.c */ 111 int acpi_md_vesa_modenum = 0; /* Referenced by arch/x86/x86/genfb_machdep.c */ 112 static int acpi_md_beep_on_reset = 0; 113 114 static int acpi_md_s4bios(void); 115 static int sysctl_md_acpi_vbios_reset(SYSCTLFN_ARGS); 116 static int sysctl_md_acpi_beep_on_reset(SYSCTLFN_ARGS); 117 118 /* Implemented in acpi_wakeup_low.S. */ 119 int acpi_md_sleep_prepare(int); 120 int acpi_md_sleep_exit(int); 121 122 /* Referenced by acpi_wakeup_low.S. */ 123 void acpi_md_sleep_enter(int); 124 125 #ifdef MULTIPROCESSOR 126 /* Referenced in ipifuncs.c. */ 127 void acpi_cpu_sleep(struct cpu_info *); 128 #endif 129 130 static void 131 acpi_md_sleep_patch(struct cpu_info *ci) 132 { 133 #define WAKECODE_FIXUP(offset, type, val) do { \ 134 type *addr; \ 135 addr = (type *)(acpi_wakeup_vaddr + offset); \ 136 *addr = val; \ 137 } while (0) 138 139 paddr_t tmp_pdir; 140 141 tmp_pdir = pmap_init_tmp_pgtbl(acpi_wakeup_paddr); 142 143 memcpy((void *)acpi_wakeup_vaddr, wakecode, sizeof(wakecode)); 144 145 if (CPU_IS_PRIMARY(ci)) { 146 WAKECODE_FIXUP(WAKEUP_vesa_modenum, uint16_t, acpi_md_vesa_modenum); 147 WAKECODE_FIXUP(WAKEUP_vbios_reset, uint8_t, acpi_md_vbios_reset); 148 WAKECODE_FIXUP(WAKEUP_beep_on_reset, uint8_t, acpi_md_beep_on_reset); 149 } else { 150 WAKECODE_FIXUP(WAKEUP_vesa_modenum, uint16_t, 0); 151 WAKECODE_FIXUP(WAKEUP_vbios_reset, uint8_t, 0); 152 WAKECODE_FIXUP(WAKEUP_beep_on_reset, uint8_t, 0); 153 } 154 155 #ifdef __i386__ 156 WAKECODE_FIXUP(WAKEUP_r_cr4, uint32_t, ci->ci_suspend_cr4); 157 #endif 158 WAKECODE_FIXUP(WAKEUP_efer, uint32_t, ci->ci_suspend_efer); 159 WAKECODE_FIXUP(WAKEUP_curcpu, void *, ci); 160 #ifdef __i386__ 161 WAKECODE_FIXUP(WAKEUP_r_cr3, uint32_t, tmp_pdir); 162 #else 163 WAKECODE_FIXUP(WAKEUP_r_cr3, uint64_t, tmp_pdir); 164 #endif 165 WAKECODE_FIXUP(WAKEUP_restorecpu, void *, acpi_md_sleep_exit); 166 #undef WAKECODE_FIXUP 167 } 168 169 static int 170 acpi_md_s4bios(void) 171 { 172 ACPI_TABLE_FACS *facs; 173 ACPI_STATUS rv; 174 175 rv = AcpiGetTable(ACPI_SIG_FACS, 0, (ACPI_TABLE_HEADER **)&facs); 176 177 if (ACPI_FAILURE(rv) || facs == NULL) 178 return 0; 179 180 if ((facs->Flags & ACPI_FACS_S4_BIOS_PRESENT) == 0) 181 return 0; 182 183 return 1; 184 } 185 186 void 187 acpi_md_sleep_enter(int state) 188 { 189 static int s4bios = -1; 190 struct cpu_info *ci; 191 ACPI_STATUS rv; 192 193 ci = curcpu(); 194 195 #ifdef MULTIPROCESSOR 196 if (!CPU_IS_PRIMARY(ci)) { 197 atomic_and_32(&ci->ci_flags, ~CPUF_RUNNING); 198 kcpuset_atomic_clear(kcpuset_running, cpu_index(ci)); 199 200 ACPI_FLUSH_CPU_CACHE(); 201 202 for (;;) 203 x86_hlt(); 204 } 205 #endif 206 207 acpi_md_sleep_patch(ci); 208 209 ACPI_FLUSH_CPU_CACHE(); 210 211 switch (state) { 212 213 case ACPI_STATE_S4: 214 215 if (s4bios < 0) 216 s4bios = acpi_md_s4bios(); 217 218 if (s4bios == 0) { 219 aprint_error("acpi0: S4 not supported\n"); 220 return; 221 } 222 223 rv = AcpiEnterSleepStateS4bios(); 224 break; 225 226 default: 227 rv = AcpiEnterSleepState(state); 228 break; 229 } 230 231 if (ACPI_FAILURE(rv)) { 232 aprint_error("acpi0: failed to enter S%d\n", state); 233 return; 234 } 235 236 for (;;) 237 x86_hlt(); 238 } 239 240 #ifdef MULTIPROCESSOR 241 void 242 acpi_cpu_sleep(struct cpu_info *ci) 243 { 244 uint64_t xcr0 = 0; 245 int s; 246 247 KASSERT(!CPU_IS_PRIMARY(ci)); 248 KASSERT(ci == curcpu()); 249 250 s = splhigh(); 251 fpu_save(); 252 x86_disable_intr(); 253 254 /* 255 * XXX also need to save the PMCs, the dbregs, and probably a few 256 * MSRs too. 257 */ 258 if (rcr4() & CR4_OSXSAVE) 259 xcr0 = rdxcr(0); 260 261 /* Go get some sleep */ 262 if (acpi_md_sleep_prepare(-1)) 263 goto out; 264 265 /* 266 * Sleeping and having bad nightmares about what could go wrong 267 * when waking up. 268 */ 269 270 /* We just woke up (cpuN), execution is resumed here */ 271 cpu_init_msrs(ci, false); 272 fpuinit(ci); 273 if (rcr4() & CR4_OSXSAVE) 274 wrxcr(0, xcr0); 275 pat_init(ci); 276 x86_errata(); 277 #if NLAPIC > 0 278 lapic_enable(); 279 lapic_set_lvt(); 280 lapic_reset(); 281 #endif 282 283 atomic_or_32(&ci->ci_flags, CPUF_RUNNING); 284 kcpuset_atomic_set(kcpuset_running, cpu_index(ci)); 285 tsc_sync_ap(ci); 286 287 out: 288 x86_enable_intr(); 289 splx(s); 290 } 291 #endif 292 293 int 294 acpi_md_sleep(int state) 295 { 296 uint64_t xcr0 = 0; 297 int s, ret = 0; 298 #ifdef MULTIPROCESSOR 299 struct cpu_info *ci; 300 CPU_INFO_ITERATOR cii; 301 cpuid_t cid; 302 #endif 303 304 KASSERT(acpi_wakeup_paddr != 0); 305 KASSERT(sizeof(wakecode) <= PAGE_SIZE); 306 307 if (!CPU_IS_PRIMARY(curcpu())) { 308 printf("acpi0: WARNING: ignoring sleep from secondary CPU\n"); 309 return -1; 310 } 311 312 AcpiSetFirmwareWakingVector(acpi_wakeup_paddr, 0); 313 314 s = splhigh(); 315 fpu_save(); 316 x86_disable_intr(); 317 318 #ifdef MULTIPROCESSOR 319 /* Save and suspend Application Processors. */ 320 x86_broadcast_ipi(X86_IPI_ACPI_CPU_SLEEP); 321 cid = cpu_index(curcpu()); 322 while (kcpuset_isotherset(kcpuset_running, cid)) { 323 delay(1); 324 } 325 #endif 326 327 /* 328 * XXX also need to save the PMCs, the dbregs, and probably a few 329 * MSRs too. 330 */ 331 if (rcr4() & CR4_OSXSAVE) 332 xcr0 = rdxcr(0); 333 334 /* Go get some sleep */ 335 if (acpi_md_sleep_prepare(state)) 336 goto out; 337 338 /* 339 * Sleeping and having bad nightmares about what could go wrong 340 * when waking up. 341 */ 342 343 /* We just woke up (cpu0), execution is resumed here */ 344 cpu_init_msrs(&cpu_info_primary, false); 345 fpuinit(&cpu_info_primary); 346 if (rcr4() & CR4_OSXSAVE) 347 wrxcr(0, xcr0); 348 pat_init(&cpu_info_primary); 349 x86_errata(); 350 i8259_reinit(); 351 #if NLAPIC > 0 352 lapic_enable(); 353 lapic_set_lvt(); 354 lapic_reset(); 355 #endif 356 #if NIOAPIC > 0 357 ioapic_reenable(); 358 #endif 359 360 initrtclock(TIMER_FREQ); 361 inittodr(time_second); 362 363 /* 364 * The BIOS should always re-enable the SCI upon 365 * resume from the S3 state. The following is a 366 * workaround for systems that fail to do this. 367 */ 368 (void)AcpiWriteBitRegister(ACPI_BITREG_SCI_ENABLE, 1); 369 370 /* 371 * Clear fixed events (see e.g. ACPI 3.0, p. 62). 372 * Also prevent GPEs from misfiring by disabling 373 * all GPEs before interrupts are enabled. The 374 * AcpiLeaveSleepState() function will enable 375 * and handle the general purpose events later. 376 */ 377 (void)AcpiClearEvent(ACPI_EVENT_PMTIMER); 378 (void)AcpiClearEvent(ACPI_EVENT_GLOBAL); 379 (void)AcpiClearEvent(ACPI_EVENT_POWER_BUTTON); 380 (void)AcpiClearEvent(ACPI_EVENT_SLEEP_BUTTON); 381 (void)AcpiClearEvent(ACPI_EVENT_RTC); 382 (void)AcpiHwDisableAllGpes(); 383 384 acpi_pci_link_resume(); 385 386 out: 387 388 #ifdef MULTIPROCESSOR 389 /* Wake up the secondary CPUs */ 390 for (CPU_INFO_FOREACH(cii, ci)) { 391 if (CPU_IS_PRIMARY(ci)) 392 continue; 393 acpi_md_sleep_patch(ci); 394 395 CPU_STARTUP(ci, acpi_wakeup_paddr); 396 CPU_START_CLEANUP(ci); 397 398 while ((ci->ci_flags & CPUF_RUNNING) == 0) 399 x86_pause(); 400 401 tsc_sync_bp(ci); 402 } 403 #endif 404 405 x86_enable_intr(); 406 splx(s); 407 408 #ifdef MTRR 409 if (mtrr_funcs != NULL) 410 mtrr_commit(); 411 #endif 412 413 return (ret); 414 } 415 416 void 417 acpi_md_sleep_init(void) 418 { 419 /* Map ACPI wakecode */ 420 acpi_wakeup_vaddr = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, 421 UVM_KMF_VAONLY); 422 if (acpi_wakeup_vaddr == 0) 423 panic("acpi: can't allocate address for wakecode.\n"); 424 425 pmap_kenter_pa(acpi_wakeup_vaddr, acpi_wakeup_paddr, 426 VM_PROT_READ | VM_PROT_WRITE, 0); 427 pmap_update(pmap_kernel()); 428 } 429 430 SYSCTL_SETUP(sysctl_md_acpi_setup, "ACPI x86 sysctl setup") 431 { 432 const struct sysctlnode *rnode; 433 int err; 434 435 err = sysctl_createv(clog, 0, NULL, &rnode, 436 CTLFLAG_PERMANENT, CTLTYPE_NODE, "acpi", NULL, 437 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); 438 439 if (err != 0) 440 return; 441 442 err = sysctl_createv(clog, 0, &rnode, &rnode, 443 CTLFLAG_PERMANENT, CTLTYPE_NODE, 444 "sleep", SYSCTL_DESCR("ACPI sleep"), 445 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); 446 447 if (err != 0) 448 return; 449 450 (void)sysctl_createv(NULL, 0, &rnode, NULL, 451 CTLFLAG_READWRITE, CTLTYPE_BOOL, "beep", 452 NULL, sysctl_md_acpi_beep_on_reset, 453 0, NULL, 0, CTL_CREATE, CTL_EOL); 454 455 (void)sysctl_createv(NULL, 0, &rnode, NULL, 456 CTLFLAG_READWRITE, CTLTYPE_INT, "vbios", 457 NULL, sysctl_md_acpi_vbios_reset, 458 0, NULL, 0, CTL_CREATE, CTL_EOL); 459 } 460 461 static int 462 sysctl_md_acpi_vbios_reset(SYSCTLFN_ARGS) 463 { 464 int error, t; 465 struct sysctlnode node; 466 467 node = *rnode; 468 t = acpi_md_vbios_reset; 469 node.sysctl_data = &t; 470 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 471 if (error || newp == NULL) 472 return error; 473 474 if (t < 0 || t > 2) 475 return EINVAL; 476 477 #ifndef VGA_POST 478 if (t == 2) { 479 aprint_error("WARNING: hw.acpi.sleep.vbios=2 " 480 "unsupported (no option VGA_POST in kernel config)\n"); 481 return EINVAL; 482 } 483 #endif 484 485 acpi_md_vbios_reset = t; 486 487 return 0; 488 } 489 490 static int 491 sysctl_md_acpi_beep_on_reset(SYSCTLFN_ARGS) 492 { 493 int error, t; 494 struct sysctlnode node; 495 496 node = *rnode; 497 t = acpi_md_beep_on_reset; 498 node.sysctl_data = &t; 499 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 500 if (error || newp == NULL) 501 return error; 502 503 if (t < 0 || t > 1) 504 return EINVAL; 505 506 acpi_md_beep_on_reset = t; 507 508 return 0; 509 } 510