acpi_wakeup.c revision 262981
1/*-
2 * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org>
3 * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
4 * Copyright (c) 2003 Peter Wemm
5 * Copyright (c) 2008-2012 Jung-uk Kim <jkim@FreeBSD.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: stable/9/sys/amd64/acpica/acpi_wakeup.c 262981 2014-03-10 20:47:24Z jkim $");
32
33#include <sys/param.h>
34#include <sys/bus.h>
35#include <sys/eventhandler.h>
36#include <sys/kernel.h>
37#include <sys/malloc.h>
38#include <sys/memrange.h>
39#include <sys/smp.h>
40
41#include <vm/vm.h>
42#include <vm/pmap.h>
43
44#include <machine/clock.h>
45#include <machine/intr_machdep.h>
46#include <x86/mca.h>
47#include <machine/pcb.h>
48#include <machine/pmap.h>
49#include <machine/specialreg.h>
50#include <machine/md_var.h>
51
52#ifdef SMP
53#include <x86/apicreg.h>
54#include <machine/smp.h>
55#include <machine/vmparam.h>
56#endif
57
58#include <contrib/dev/acpica/include/acpi.h>
59
60#include <dev/acpica/acpivar.h>
61
62#include "acpi_wakecode.h"
63#include "acpi_wakedata.h"
64
65/* Make sure the code is less than a page and leave room for the stack. */
66CTASSERT(sizeof(wakecode) < PAGE_SIZE - 1024);
67
68extern int		acpi_resume_beep;
69extern int		acpi_reset_video;
70
71#ifdef SMP
72extern struct pcb	**susppcbs;
73extern void		**suspfpusave;
74#else
75static struct pcb	**susppcbs;
76static void		**suspfpusave;
77#endif
78
79#ifdef SMP
80static cpuset_t		suspcpus;
81#endif
82
83int			acpi_restorecpu(uint64_t, vm_offset_t);
84
85static void		*acpi_alloc_wakeup_handler(void);
86static void		acpi_stop_beep(void *);
87
88#ifdef SMP
89static int		acpi_wakeup_ap(struct acpi_softc *, int);
90static void		acpi_wakeup_cpus(struct acpi_softc *, const cpuset_t *);
91#endif
92
93#define	WAKECODE_VADDR(sc)	((sc)->acpi_wakeaddr + (3 * PAGE_SIZE))
94#define	WAKECODE_PADDR(sc)	((sc)->acpi_wakephys + (3 * PAGE_SIZE))
95#define	WAKECODE_FIXUP(offset, type, val) do	{	\
96	type	*addr;					\
97	addr = (type *)(WAKECODE_VADDR(sc) + offset);	\
98	*addr = val;					\
99} while (0)
100
101static void
102acpi_stop_beep(void *arg)
103{
104
105	if (acpi_resume_beep != 0)
106		timer_spkr_release();
107}
108
109#ifdef SMP
110static int
111acpi_wakeup_ap(struct acpi_softc *sc, int cpu)
112{
113	int		vector = (WAKECODE_PADDR(sc) >> 12) & 0xff;
114	int		apic_id = cpu_apic_ids[cpu];
115	int		ms;
116
117	WAKECODE_FIXUP(wakeup_pcb, struct pcb *, susppcbs[cpu]);
118	WAKECODE_FIXUP(wakeup_fpusave, void *, suspfpusave[cpu]);
119	WAKECODE_FIXUP(wakeup_gdt, uint16_t, susppcbs[cpu]->pcb_gdt.rd_limit);
120	WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t,
121	    susppcbs[cpu]->pcb_gdt.rd_base);
122	WAKECODE_FIXUP(wakeup_cpu, int, cpu);
123
124	/* do an INIT IPI: assert RESET */
125	lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
126	    APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT, apic_id);
127
128	/* wait for pending status end */
129	lapic_ipi_wait(-1);
130
131	/* do an INIT IPI: deassert RESET */
132	lapic_ipi_raw(APIC_DEST_ALLESELF | APIC_TRIGMOD_LEVEL |
133	    APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT, 0);
134
135	/* wait for pending status end */
136	DELAY(10000);		/* wait ~10mS */
137	lapic_ipi_wait(-1);
138
139	/*
140	 * next we do a STARTUP IPI: the previous INIT IPI might still be
141	 * latched, (P5 bug) this 1st STARTUP would then terminate
142	 * immediately, and the previously started INIT IPI would continue. OR
143	 * the previous INIT IPI has already run. and this STARTUP IPI will
144	 * run. OR the previous INIT IPI was ignored. and this STARTUP IPI
145	 * will run.
146	 */
147
148	/* do a STARTUP IPI */
149	lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
150	    APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
151	    vector, apic_id);
152	lapic_ipi_wait(-1);
153	DELAY(200);		/* wait ~200uS */
154
155	/*
156	 * finally we do a 2nd STARTUP IPI: this 2nd STARTUP IPI should run IF
157	 * the previous STARTUP IPI was cancelled by a latched INIT IPI. OR
158	 * this STARTUP IPI will be ignored, as only ONE STARTUP IPI is
159	 * recognized after hardware RESET or INIT IPI.
160	 */
161
162	lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
163	    APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
164	    vector, apic_id);
165	lapic_ipi_wait(-1);
166	DELAY(200);		/* wait ~200uS */
167
168	/* Wait up to 5 seconds for it to start. */
169	for (ms = 0; ms < 5000; ms++) {
170		if (*(int *)(WAKECODE_VADDR(sc) + wakeup_cpu) == 0)
171			return (1);	/* return SUCCESS */
172		DELAY(1000);
173	}
174	return (0);		/* return FAILURE */
175}
176
177#define	WARMBOOT_TARGET		0
178#define	WARMBOOT_OFF		(KERNBASE + 0x0467)
179#define	WARMBOOT_SEG		(KERNBASE + 0x0469)
180
181#define	CMOS_REG		(0x70)
182#define	CMOS_DATA		(0x71)
183#define	BIOS_RESET		(0x0f)
184#define	BIOS_WARM		(0x0a)
185
186static void
187acpi_wakeup_cpus(struct acpi_softc *sc, const cpuset_t *wakeup_cpus)
188{
189	uint32_t	mpbioswarmvec;
190	int		cpu;
191	u_char		mpbiosreason;
192
193	/* save the current value of the warm-start vector */
194	mpbioswarmvec = *((uint32_t *)WARMBOOT_OFF);
195	outb(CMOS_REG, BIOS_RESET);
196	mpbiosreason = inb(CMOS_DATA);
197
198	/* setup a vector to our boot code */
199	*((volatile u_short *)WARMBOOT_OFF) = WARMBOOT_TARGET;
200	*((volatile u_short *)WARMBOOT_SEG) = WAKECODE_PADDR(sc) >> 4;
201	outb(CMOS_REG, BIOS_RESET);
202	outb(CMOS_DATA, BIOS_WARM);	/* 'warm-start' */
203
204	/* Wake up each AP. */
205	for (cpu = 1; cpu < mp_ncpus; cpu++) {
206		if (!CPU_ISSET(cpu, wakeup_cpus))
207			continue;
208		if (acpi_wakeup_ap(sc, cpu) == 0) {
209			/* restore the warmstart vector */
210			*(uint32_t *)WARMBOOT_OFF = mpbioswarmvec;
211			panic("acpi_wakeup: failed to resume AP #%d (PHY #%d)",
212			    cpu, cpu_apic_ids[cpu]);
213		}
214	}
215
216	/* restore the warmstart vector */
217	*(uint32_t *)WARMBOOT_OFF = mpbioswarmvec;
218
219	outb(CMOS_REG, BIOS_RESET);
220	outb(CMOS_DATA, mpbiosreason);
221}
222#endif
223
224int
225acpi_sleep_machdep(struct acpi_softc *sc, int state)
226{
227	ACPI_STATUS	status;
228
229	if (sc->acpi_wakeaddr == 0ul)
230		return (-1);	/* couldn't alloc wake memory */
231
232#ifdef SMP
233	suspcpus = all_cpus;
234	CPU_CLR(PCPU_GET(cpuid), &suspcpus);
235#endif
236
237	if (acpi_resume_beep != 0)
238		timer_spkr_acquire();
239
240	AcpiSetFirmwareWakingVector(WAKECODE_PADDR(sc));
241
242	intr_suspend();
243
244	if (savectx(susppcbs[0])) {
245		fpususpend(suspfpusave[0]);
246#ifdef SMP
247		if (!CPU_EMPTY(&suspcpus) &&
248		    suspend_cpus(suspcpus) == 0) {
249			device_printf(sc->acpi_dev, "Failed to suspend APs\n");
250			return (0);	/* couldn't sleep */
251		}
252#endif
253
254		WAKECODE_FIXUP(resume_beep, uint8_t, (acpi_resume_beep != 0));
255		WAKECODE_FIXUP(reset_video, uint8_t, (acpi_reset_video != 0));
256
257		WAKECODE_FIXUP(wakeup_pcb, struct pcb *, susppcbs[0]);
258		WAKECODE_FIXUP(wakeup_fpusave, void *, suspfpusave[0]);
259		WAKECODE_FIXUP(wakeup_gdt, uint16_t,
260		    susppcbs[0]->pcb_gdt.rd_limit);
261		WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t,
262		    susppcbs[0]->pcb_gdt.rd_base);
263		WAKECODE_FIXUP(wakeup_cpu, int, 0);
264
265		/* Call ACPICA to enter the desired sleep state */
266		if (state == ACPI_STATE_S4 && sc->acpi_s4bios)
267			status = AcpiEnterSleepStateS4bios();
268		else
269			status = AcpiEnterSleepState(state);
270
271		if (status != AE_OK) {
272			device_printf(sc->acpi_dev,
273			    "AcpiEnterSleepState failed - %s\n",
274			    AcpiFormatException(status));
275			return (0);	/* couldn't sleep */
276		}
277
278		for (;;)
279			ia32_pause();
280	}
281
282	return (1);	/* wakeup successfully */
283}
284
285int
286acpi_wakeup_machdep(struct acpi_softc *sc, int state,
287    int sleep_result, int intr_enabled)
288{
289
290	if (sleep_result == -1)
291		return (sleep_result);
292
293	if (intr_enabled == 0) {
294		/* Wakeup MD procedures in interrupt disabled context */
295		if (sleep_result == 1) {
296			pmap_init_pat();
297			load_cr3(susppcbs[0]->pcb_cr3);
298			initializecpu();
299			PCPU_SET(switchtime, 0);
300			PCPU_SET(switchticks, ticks);
301#ifdef SMP
302			if (!CPU_EMPTY(&suspcpus))
303				acpi_wakeup_cpus(sc, &suspcpus);
304#endif
305		}
306
307#ifdef SMP
308		if (!CPU_EMPTY(&suspcpus))
309			restart_cpus(suspcpus);
310#endif
311		mca_resume();
312		intr_resume();
313	} else {
314		/* Wakeup MD procedures in interrupt enabled context */
315		AcpiSetFirmwareWakingVector(0);
316
317		if (sleep_result == 1 && mem_range_softc.mr_op != NULL &&
318		    mem_range_softc.mr_op->reinit != NULL)
319			mem_range_softc.mr_op->reinit(&mem_range_softc);
320	}
321
322	return (sleep_result);
323}
324
325static void *
326acpi_alloc_wakeup_handler(void)
327{
328	void		*wakeaddr;
329	int		i;
330
331	/*
332	 * Specify the region for our wakeup code.  We want it in the low 1 MB
333	 * region, excluding real mode IVT (0-0x3ff), BDA (0x400-0x4ff), EBDA
334	 * (less than 128KB, below 0xa0000, must be excluded by SMAP and DSDT),
335	 * and ROM area (0xa0000 and above).  The temporary page tables must be
336	 * page-aligned.
337	 */
338	wakeaddr = contigmalloc(4 * PAGE_SIZE, M_DEVBUF, M_WAITOK, 0x500,
339	    0xa0000, PAGE_SIZE, 0ul);
340	if (wakeaddr == NULL) {
341		printf("%s: can't alloc wake memory\n", __func__);
342		return (NULL);
343	}
344	if (EVENTHANDLER_REGISTER(power_resume, acpi_stop_beep, NULL,
345	    EVENTHANDLER_PRI_LAST) == NULL) {
346		printf("%s: can't register event handler\n", __func__);
347		contigfree(wakeaddr, 4 * PAGE_SIZE, M_DEVBUF);
348		return (NULL);
349	}
350	susppcbs = malloc(mp_ncpus * sizeof(*susppcbs), M_DEVBUF, M_WAITOK);
351	suspfpusave = malloc(mp_ncpus * sizeof(void *), M_DEVBUF, M_WAITOK);
352	for (i = 0; i < mp_ncpus; i++) {
353		susppcbs[i] = malloc(sizeof(**susppcbs), M_DEVBUF, M_WAITOK);
354		suspfpusave[i] = alloc_fpusave(M_WAITOK);
355	}
356
357	return (wakeaddr);
358}
359
360void
361acpi_install_wakeup_handler(struct acpi_softc *sc)
362{
363	static void	*wakeaddr = NULL;
364	uint64_t	*pt4, *pt3, *pt2;
365	int		i;
366
367	if (wakeaddr != NULL)
368		return;
369
370	wakeaddr = acpi_alloc_wakeup_handler();
371	if (wakeaddr == NULL)
372		return;
373
374	sc->acpi_wakeaddr = (vm_offset_t)wakeaddr;
375	sc->acpi_wakephys = vtophys(wakeaddr);
376
377	bcopy(wakecode, (void *)WAKECODE_VADDR(sc), sizeof(wakecode));
378
379	/* Patch GDT base address, ljmp targets and page table base address. */
380	WAKECODE_FIXUP((bootgdtdesc + 2), uint32_t,
381	    WAKECODE_PADDR(sc) + bootgdt);
382	WAKECODE_FIXUP((wakeup_sw32 + 2), uint32_t,
383	    WAKECODE_PADDR(sc) + wakeup_32);
384	WAKECODE_FIXUP((wakeup_sw64 + 1), uint32_t,
385	    WAKECODE_PADDR(sc) + wakeup_64);
386	WAKECODE_FIXUP(wakeup_pagetables, uint32_t, sc->acpi_wakephys);
387
388	/* Save pointers to some global data. */
389	WAKECODE_FIXUP(wakeup_retaddr, void *, acpi_restorecpu);
390	WAKECODE_FIXUP(wakeup_kpml4, uint64_t, KPML4phys);
391	WAKECODE_FIXUP(wakeup_ctx, vm_offset_t,
392	    WAKECODE_VADDR(sc) + wakeup_ctx);
393	WAKECODE_FIXUP(wakeup_efer, uint64_t, rdmsr(MSR_EFER));
394	WAKECODE_FIXUP(wakeup_star, uint64_t, rdmsr(MSR_STAR));
395	WAKECODE_FIXUP(wakeup_lstar, uint64_t, rdmsr(MSR_LSTAR));
396	WAKECODE_FIXUP(wakeup_cstar, uint64_t, rdmsr(MSR_CSTAR));
397	WAKECODE_FIXUP(wakeup_sfmask, uint64_t, rdmsr(MSR_SF_MASK));
398	WAKECODE_FIXUP(wakeup_xsmask, uint64_t, xsave_mask);
399
400	/* Build temporary page tables below realmode code. */
401	pt4 = wakeaddr;
402	pt3 = pt4 + (PAGE_SIZE) / sizeof(uint64_t);
403	pt2 = pt3 + (PAGE_SIZE) / sizeof(uint64_t);
404
405	/* Create the initial 1GB replicated page tables */
406	for (i = 0; i < 512; i++) {
407		/*
408		 * Each slot of the level 4 pages points
409		 * to the same level 3 page
410		 */
411		pt4[i] = (uint64_t)(sc->acpi_wakephys + PAGE_SIZE);
412		pt4[i] |= PG_V | PG_RW | PG_U;
413
414		/*
415		 * Each slot of the level 3 pages points
416		 * to the same level 2 page
417		 */
418		pt3[i] = (uint64_t)(sc->acpi_wakephys + (2 * PAGE_SIZE));
419		pt3[i] |= PG_V | PG_RW | PG_U;
420
421		/* The level 2 page slots are mapped with 2MB pages for 1GB. */
422		pt2[i] = i * (2 * 1024 * 1024);
423		pt2[i] |= PG_V | PG_RW | PG_PS | PG_U;
424	}
425
426	if (bootverbose)
427		device_printf(sc->acpi_dev, "wakeup code va %p pa %p\n",
428		    (void *)sc->acpi_wakeaddr, (void *)sc->acpi_wakephys);
429}
430