]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/x86/acpica/acpi_wakeup.c
MFS r353173:
[FreeBSD/FreeBSD.git] / sys / x86 / acpica / acpi_wakeup.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org>
5  * Copyright (c) 2001-2012 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
6  * Copyright (c) 2003 Peter Wemm
7  * Copyright (c) 2008-2012 Jung-uk Kim <jkim@FreeBSD.org>
8  * All rights reserved.
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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #if defined(__amd64__)
36 #define DEV_APIC
37 #else
38 #include "opt_apic.h"
39 #endif
40
41 #include <sys/param.h>
42 #include <sys/bus.h>
43 #include <sys/eventhandler.h>
44 #include <sys/kernel.h>
45 #include <sys/malloc.h>
46 #include <sys/memrange.h>
47 #include <sys/smp.h>
48 #include <sys/systm.h>
49 #include <sys/cons.h>
50
51 #include <vm/vm.h>
52 #include <vm/pmap.h>
53
54 #include <machine/clock.h>
55 #include <machine/cpu.h>
56 #include <machine/intr_machdep.h>
57 #include <machine/md_var.h>
58 #include <x86/mca.h>
59 #include <machine/pcb.h>
60 #include <machine/specialreg.h>
61 #include <x86/ucode.h>
62
63 #ifdef DEV_APIC
64 #include <x86/apicreg.h>
65 #include <x86/apicvar.h>
66 #endif
67 #ifdef SMP
68 #include <machine/smp.h>
69 #include <machine/vmparam.h>
70 #endif
71
72 #include <contrib/dev/acpica/include/acpi.h>
73
74 #include <dev/acpica/acpivar.h>
75
76 #include "acpi_wakecode.h"
77 #include "acpi_wakedata.h"
78
79 /* Make sure the code is less than a page and leave room for the stack. */
80 CTASSERT(sizeof(wakecode) < PAGE_SIZE - 1024);
81
82 extern int              acpi_resume_beep;
83 extern int              acpi_reset_video;
84 extern int              acpi_susp_bounce;
85
86 #ifdef SMP
87 extern struct susppcb   **susppcbs;
88 static cpuset_t         suspcpus;
89 #else
90 static struct susppcb   **susppcbs;
91 #endif
92
93 static void             *acpi_alloc_wakeup_handler(void **);
94 static void             acpi_stop_beep(void *);
95
96 #ifdef SMP
97 static int              acpi_wakeup_ap(struct acpi_softc *, int);
98 static void             acpi_wakeup_cpus(struct acpi_softc *);
99 #endif
100
101 #ifdef __amd64__
102 #define ACPI_WAKEPAGES  4
103 #else
104 #define ACPI_WAKEPAGES  1
105 #endif
106
107 #define WAKECODE_FIXUP(offset, type, val)       do {    \
108         type    *addr;                                  \
109         addr = (type *)(sc->acpi_wakeaddr + (offset));  \
110         *addr = val;                                    \
111 } while (0)
112
113 static void
114 acpi_stop_beep(void *arg)
115 {
116
117         if (acpi_resume_beep != 0)
118                 timer_spkr_release();
119 }
120
121 #ifdef SMP
122 static int
123 acpi_wakeup_ap(struct acpi_softc *sc, int cpu)
124 {
125         struct pcb *pcb;
126         int             vector = (sc->acpi_wakephys >> 12) & 0xff;
127         int             apic_id = cpu_apic_ids[cpu];
128         int             ms;
129
130         pcb = &susppcbs[cpu]->sp_pcb;
131         WAKECODE_FIXUP(wakeup_pcb, struct pcb *, pcb);
132         WAKECODE_FIXUP(wakeup_gdt, uint16_t, pcb->pcb_gdt.rd_limit);
133         WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t, pcb->pcb_gdt.rd_base);
134
135         ipi_startup(apic_id, vector);
136
137         /* Wait up to 5 seconds for it to resume. */
138         for (ms = 0; ms < 5000; ms++) {
139                 if (!CPU_ISSET(cpu, &suspended_cpus))
140                         return (1);     /* return SUCCESS */
141                 DELAY(1000);
142         }
143         return (0);             /* return FAILURE */
144 }
145
146 #define WARMBOOT_TARGET         0
147 #ifdef __amd64__
148 #define WARMBOOT_OFF            (KERNBASE + 0x0467)
149 #define WARMBOOT_SEG            (KERNBASE + 0x0469)
150 #else /* __i386__ */
151 #define WARMBOOT_OFF            (PMAP_MAP_LOW + 0x0467)
152 #define WARMBOOT_SEG            (PMAP_MAP_LOW + 0x0469)
153 #endif
154
155 #define CMOS_REG                (0x70)
156 #define CMOS_DATA               (0x71)
157 #define BIOS_RESET              (0x0f)
158 #define BIOS_WARM               (0x0a)
159
160 static void
161 acpi_wakeup_cpus(struct acpi_softc *sc)
162 {
163         uint32_t        mpbioswarmvec;
164         int             cpu;
165         u_char          mpbiosreason;
166
167         /* save the current value of the warm-start vector */
168         mpbioswarmvec = *((uint32_t *)WARMBOOT_OFF);
169         outb(CMOS_REG, BIOS_RESET);
170         mpbiosreason = inb(CMOS_DATA);
171
172         /* setup a vector to our boot code */
173         *((volatile u_short *)WARMBOOT_OFF) = WARMBOOT_TARGET;
174         *((volatile u_short *)WARMBOOT_SEG) = sc->acpi_wakephys >> 4;
175         outb(CMOS_REG, BIOS_RESET);
176         outb(CMOS_DATA, BIOS_WARM);     /* 'warm-start' */
177
178         /* Wake up each AP. */
179         for (cpu = 1; cpu < mp_ncpus; cpu++) {
180                 if (!CPU_ISSET(cpu, &suspcpus))
181                         continue;
182                 if (acpi_wakeup_ap(sc, cpu) == 0) {
183                         /* restore the warmstart vector */
184                         *(uint32_t *)WARMBOOT_OFF = mpbioswarmvec;
185                         panic("acpi_wakeup: failed to resume AP #%d (PHY #%d)",
186                             cpu, cpu_apic_ids[cpu]);
187                 }
188         }
189
190 #ifdef __i386__
191         /*
192          * Remove the identity mapping of low memory for all CPUs and sync
193          * the TLB for the BSP.  The APs are now spinning in
194          * cpususpend_handler() and we will release them soon.  Then each
195          * will invalidate its TLB.
196          */
197         PTD[KPTDI] = 0;
198         invltlb_glob();
199 #endif
200
201         /* restore the warmstart vector */
202         *(uint32_t *)WARMBOOT_OFF = mpbioswarmvec;
203
204         outb(CMOS_REG, BIOS_RESET);
205         outb(CMOS_DATA, mpbiosreason);
206 }
207 #endif
208
209 int
210 acpi_sleep_machdep(struct acpi_softc *sc, int state)
211 {
212         ACPI_STATUS     status;
213         struct pcb      *pcb;
214 #ifdef __amd64__
215         struct pcpu *pc;
216         int i;
217 #endif
218
219         if (sc->acpi_wakeaddr == 0ul)
220                 return (-1);    /* couldn't alloc wake memory */
221
222 #ifdef SMP
223         suspcpus = all_cpus;
224         CPU_CLR(PCPU_GET(cpuid), &suspcpus);
225 #endif
226
227         if (acpi_resume_beep != 0)
228                 timer_spkr_acquire();
229
230         AcpiSetFirmwareWakingVector(sc->acpi_wakephys, 0);
231
232         intr_suspend();
233
234         pcb = &susppcbs[0]->sp_pcb;
235         if (savectx(pcb)) {
236 #ifdef __amd64__
237                 fpususpend(susppcbs[0]->sp_fpususpend);
238 #else
239                 npxsuspend(susppcbs[0]->sp_fpususpend);
240 #endif
241 #ifdef SMP
242                 if (!CPU_EMPTY(&suspcpus) && suspend_cpus(suspcpus) == 0) {
243                         device_printf(sc->acpi_dev, "Failed to suspend APs\n");
244                         return (0);     /* couldn't sleep */
245                 }
246 #endif
247 #ifdef __amd64__
248                 hw_ibrs_active = 0;
249                 hw_ssb_active = 0;
250                 cpu_stdext_feature3 = 0;
251                 CPU_FOREACH(i) {
252                         pc = pcpu_find(i);
253                         pc->pc_ibpb_set = 0;
254                 }
255 #endif
256
257                 WAKECODE_FIXUP(resume_beep, uint8_t, (acpi_resume_beep != 0));
258                 WAKECODE_FIXUP(reset_video, uint8_t, (acpi_reset_video != 0));
259
260 #ifdef __amd64__
261                 WAKECODE_FIXUP(wakeup_efer, uint64_t, rdmsr(MSR_EFER) &
262                     ~(EFER_LMA));
263 #else
264                 WAKECODE_FIXUP(wakeup_cr4, register_t, pcb->pcb_cr4);
265 #endif
266                 WAKECODE_FIXUP(wakeup_pcb, struct pcb *, pcb);
267                 WAKECODE_FIXUP(wakeup_gdt, uint16_t, pcb->pcb_gdt.rd_limit);
268                 WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t, pcb->pcb_gdt.rd_base);
269
270 #ifdef __i386__
271                 /*
272                  * Map some low memory with virt == phys for ACPI wakecode
273                  * to use to jump to high memory after enabling paging. This
274                  * is the same as for similar jump in locore, except the
275                  * jump is a single instruction, and we know its address
276                  * more precisely so only need a single PTD, and we have to
277                  * be careful to use the kernel map (PTD[0] is for curthread
278                  * which may be a user thread in deprecated APIs).
279                  */
280                 PTD[KPTDI] = PTD[LOWPTDI];
281 #endif
282
283                 /* Call ACPICA to enter the desired sleep state */
284                 if (state == ACPI_STATE_S4 && sc->acpi_s4bios)
285                         status = AcpiEnterSleepStateS4bios();
286                 else
287                         status = AcpiEnterSleepState(state);
288                 if (ACPI_FAILURE(status)) {
289                         device_printf(sc->acpi_dev,
290                             "AcpiEnterSleepState failed - %s\n",
291                             AcpiFormatException(status));
292                         return (0);     /* couldn't sleep */
293                 }
294
295                 if (acpi_susp_bounce)
296                         resumectx(pcb);
297
298                 for (;;)
299                         ia32_pause();
300         } else {
301                 /*
302                  * Re-initialize console hardware as soon as possibe.
303                  * No console output (e.g. printf) is allowed before
304                  * this point.
305                  */
306                 cnresume();
307 #ifdef __amd64__
308                 fpuresume(susppcbs[0]->sp_fpususpend);
309 #else
310                 npxresume(susppcbs[0]->sp_fpususpend);
311 #endif
312         }
313
314         return (1);     /* wakeup successfully */
315 }
316
317 int
318 acpi_wakeup_machdep(struct acpi_softc *sc, int state, int sleep_result,
319     int intr_enabled)
320 {
321
322         if (sleep_result == -1)
323                 return (sleep_result);
324
325         if (!intr_enabled) {
326                 /* Wakeup MD procedures in interrupt disabled context */
327                 if (sleep_result == 1) {
328                         ucode_reload();
329                         pmap_init_pat();
330                         initializecpu();
331                         PCPU_SET(switchtime, 0);
332                         PCPU_SET(switchticks, ticks);
333 #ifdef DEV_APIC
334                         lapic_xapic_mode();
335 #endif
336 #ifdef SMP
337                         if (!CPU_EMPTY(&suspcpus))
338                                 acpi_wakeup_cpus(sc);
339 #endif
340                 }
341
342 #ifdef SMP
343                 if (!CPU_EMPTY(&suspcpus))
344                         resume_cpus(suspcpus);
345 #endif
346                 mca_resume();
347 #ifdef __amd64__
348                 if (vmm_resume_p != NULL)
349                         vmm_resume_p();
350 #endif
351                 intr_resume(/*suspend_cancelled*/false);
352
353                 AcpiSetFirmwareWakingVector(0, 0);
354         } else {
355                 /* Wakeup MD procedures in interrupt enabled context */
356                 if (sleep_result == 1 && mem_range_softc.mr_op != NULL &&
357                     mem_range_softc.mr_op->reinit != NULL)
358                         mem_range_softc.mr_op->reinit(&mem_range_softc);
359         }
360
361         return (sleep_result);
362 }
363
364 static void *
365 acpi_alloc_wakeup_handler(void *wakepages[ACPI_WAKEPAGES])
366 {
367         int             i;
368
369         memset(wakepages, 0, ACPI_WAKEPAGES * sizeof(*wakepages));
370
371         /*
372          * Specify the region for our wakeup code.  We want it in the low 1 MB
373          * region, excluding real mode IVT (0-0x3ff), BDA (0x400-0x4ff), EBDA
374          * (less than 128KB, below 0xa0000, must be excluded by SMAP and DSDT),
375          * and ROM area (0xa0000 and above).  The temporary page tables must be
376          * page-aligned.
377          */
378         for (i = 0; i < ACPI_WAKEPAGES; i++) {
379                 wakepages[i] = contigmalloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT,
380                     0x500, 0xa0000, PAGE_SIZE, 0ul);
381                 if (wakepages[i] == NULL) {
382                         printf("%s: can't alloc wake memory\n", __func__);
383                         goto freepages;
384                 }
385         }
386         if (EVENTHANDLER_REGISTER(power_resume, acpi_stop_beep, NULL,
387             EVENTHANDLER_PRI_LAST) == NULL) {
388                 printf("%s: can't register event handler\n", __func__);
389                 goto freepages;
390         }
391         susppcbs = malloc(mp_ncpus * sizeof(*susppcbs), M_DEVBUF, M_WAITOK);
392         for (i = 0; i < mp_ncpus; i++) {
393                 susppcbs[i] = malloc(sizeof(**susppcbs), M_DEVBUF, M_WAITOK);
394                 susppcbs[i]->sp_fpususpend = alloc_fpusave(M_WAITOK);
395         }
396
397         return (wakepages);
398
399 freepages:
400         for (i = 0; i < ACPI_WAKEPAGES; i++)
401                 if (wakepages[i] != NULL)
402                         contigfree(wakepages[i], PAGE_SIZE, M_DEVBUF);
403         return (NULL);
404 }
405
406 void
407 acpi_install_wakeup_handler(struct acpi_softc *sc)
408 {
409         static void     *wakeaddr;
410         void            *wakepages[ACPI_WAKEPAGES];
411 #ifdef __amd64__
412         uint64_t        *pt4, *pt3, *pt2;
413         vm_paddr_t      pt4pa, pt3pa, pt2pa;
414         int             i;
415 #endif
416
417         if (wakeaddr != NULL)
418                 return;
419
420         if (acpi_alloc_wakeup_handler(wakepages) == NULL)
421                 return;
422
423         wakeaddr = wakepages[0];
424         sc->acpi_wakeaddr = (vm_offset_t)wakeaddr;
425         sc->acpi_wakephys = vtophys(wakeaddr);
426
427 #ifdef __amd64__
428         pt4 = wakepages[1];
429         pt3 = wakepages[2];
430         pt2 = wakepages[3];
431         pt4pa = vtophys(pt4);
432         pt3pa = vtophys(pt3);
433         pt2pa = vtophys(pt2);
434 #endif
435
436         bcopy(wakecode, (void *)sc->acpi_wakeaddr, sizeof(wakecode));
437
438         /* Patch GDT base address, ljmp targets. */
439         WAKECODE_FIXUP((bootgdtdesc + 2), uint32_t,
440             sc->acpi_wakephys + bootgdt);
441         WAKECODE_FIXUP((wakeup_sw32 + 2), uint32_t,
442             sc->acpi_wakephys + wakeup_32);
443 #ifdef __amd64__
444         WAKECODE_FIXUP((wakeup_sw64 + 1), uint32_t,
445             sc->acpi_wakephys + wakeup_64);
446         WAKECODE_FIXUP(wakeup_pagetables, uint32_t, pt4pa);
447 #endif
448
449         /* Save pointers to some global data. */
450         WAKECODE_FIXUP(wakeup_ret, void *, resumectx);
451 #ifndef __amd64__
452 #if defined(PAE) || defined(PAE_TABLES)
453         WAKECODE_FIXUP(wakeup_cr3, register_t, vtophys(kernel_pmap->pm_pdpt));
454 #else
455         WAKECODE_FIXUP(wakeup_cr3, register_t, vtophys(kernel_pmap->pm_pdir));
456 #endif
457
458 #else /* __amd64__ */
459         /* Create the initial 1GB replicated page tables */
460         for (i = 0; i < 512; i++) {
461                 /*
462                  * Each slot of the level 4 pages points
463                  * to the same level 3 page
464                  */
465                 pt4[i] = (uint64_t)pt3pa;
466                 pt4[i] |= PG_V | PG_RW | PG_U;
467
468                 /*
469                  * Each slot of the level 3 pages points
470                  * to the same level 2 page
471                  */
472                 pt3[i] = (uint64_t)pt2pa;
473                 pt3[i] |= PG_V | PG_RW | PG_U;
474
475                 /* The level 2 page slots are mapped with 2MB pages for 1GB. */
476                 pt2[i] = i * (2 * 1024 * 1024);
477                 pt2[i] |= PG_V | PG_RW | PG_PS | PG_U;
478         }
479 #endif /* !__amd64__ */
480
481         if (bootverbose)
482                 device_printf(sc->acpi_dev, "wakeup code va %#jx pa %#jx\n",
483                     (uintmax_t)sc->acpi_wakeaddr, (uintmax_t)sc->acpi_wakephys);
484 }