2001-07-20 06:07:34 +00:00
|
|
|
/*-
|
2017-11-27 15:11:47 +00:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
|
|
|
*
|
2001-07-20 06:07:34 +00:00
|
|
|
* Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org>
|
2012-06-09 00:37:26 +00:00
|
|
|
* Copyright (c) 2001-2012 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
|
2009-03-17 00:48:11 +00:00
|
|
|
* Copyright (c) 2003 Peter Wemm
|
2012-01-31 17:51:30 +00:00
|
|
|
* Copyright (c) 2008-2012 Jung-uk Kim <jkim@FreeBSD.org>
|
2001-07-20 06:07:34 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
2003-07-25 21:10:19 +00:00
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
2015-02-20 19:42:26 +00:00
|
|
|
#include "opt_apic.h"
|
2014-08-30 17:48:38 +00:00
|
|
|
|
2001-07-20 06:07:34 +00:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/bus.h>
|
2012-02-15 22:49:25 +00:00
|
|
|
#include <sys/eventhandler.h>
|
2009-03-17 00:48:11 +00:00
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/memrange.h>
|
|
|
|
#include <sys/smp.h>
|
2013-12-24 14:48:52 +00:00
|
|
|
#include <sys/systm.h>
|
2018-05-29 16:16:24 +00:00
|
|
|
#include <sys/cons.h>
|
2009-03-17 00:48:11 +00:00
|
|
|
|
|
|
|
#include <vm/vm.h>
|
|
|
|
#include <vm/pmap.h>
|
|
|
|
|
2012-02-15 22:49:25 +00:00
|
|
|
#include <machine/clock.h>
|
2013-12-23 19:48:22 +00:00
|
|
|
#include <machine/cpu.h>
|
2009-03-17 00:48:11 +00:00
|
|
|
#include <machine/intr_machdep.h>
|
2018-08-13 17:13:09 +00:00
|
|
|
#include <machine/md_var.h>
|
2010-11-01 17:40:35 +00:00
|
|
|
#include <x86/mca.h>
|
2009-03-17 00:48:11 +00:00
|
|
|
#include <machine/pcb.h>
|
|
|
|
#include <machine/specialreg.h>
|
2018-08-13 17:13:09 +00:00
|
|
|
#include <x86/ucode.h>
|
2009-03-17 00:48:11 +00:00
|
|
|
|
2015-02-20 19:42:26 +00:00
|
|
|
#ifdef DEV_APIC
|
2010-11-01 18:18:46 +00:00
|
|
|
#include <x86/apicreg.h>
|
2015-02-18 10:51:48 +00:00
|
|
|
#include <x86/apicvar.h>
|
2015-02-20 19:42:26 +00:00
|
|
|
#endif
|
2015-02-18 10:51:48 +00:00
|
|
|
#ifdef SMP
|
2009-03-17 00:48:11 +00:00
|
|
|
#include <machine/smp.h>
|
2009-10-08 17:41:53 +00:00
|
|
|
#include <machine/vmparam.h>
|
2009-03-17 00:48:11 +00:00
|
|
|
#endif
|
2001-07-20 06:07:34 +00:00
|
|
|
|
2009-06-05 18:44:36 +00:00
|
|
|
#include <contrib/dev/acpica/include/acpi.h>
|
|
|
|
|
2001-07-20 06:07:34 +00:00
|
|
|
#include <dev/acpica/acpivar.h>
|
|
|
|
|
2009-03-17 00:48:11 +00:00
|
|
|
#include "acpi_wakecode.h"
|
|
|
|
#include "acpi_wakedata.h"
|
|
|
|
|
|
|
|
/* Make sure the code is less than a page and leave room for the stack. */
|
|
|
|
CTASSERT(sizeof(wakecode) < PAGE_SIZE - 1024);
|
|
|
|
|
2009-03-23 22:35:30 +00:00
|
|
|
extern int acpi_resume_beep;
|
|
|
|
extern int acpi_reset_video;
|
2018-05-03 19:00:50 +00:00
|
|
|
extern int acpi_susp_bounce;
|
2009-03-17 00:48:11 +00:00
|
|
|
|
|
|
|
#ifdef SMP
|
2014-09-06 15:23:28 +00:00
|
|
|
extern struct susppcb **susppcbs;
|
2012-06-01 19:19:04 +00:00
|
|
|
static cpuset_t suspcpus;
|
2009-03-17 00:48:11 +00:00
|
|
|
#else
|
2014-09-06 15:23:28 +00:00
|
|
|
static struct susppcb **susppcbs;
|
2009-03-17 00:48:11 +00:00
|
|
|
#endif
|
|
|
|
|
2016-07-14 00:38:04 +00:00
|
|
|
static void *acpi_alloc_wakeup_handler(void **);
|
2009-03-17 00:48:11 +00:00
|
|
|
static void acpi_stop_beep(void *);
|
|
|
|
|
|
|
|
#ifdef SMP
|
|
|
|
static int acpi_wakeup_ap(struct acpi_softc *, int);
|
2012-06-01 19:19:04 +00:00
|
|
|
static void acpi_wakeup_cpus(struct acpi_softc *);
|
2009-03-17 00:48:11 +00:00
|
|
|
#endif
|
|
|
|
|
2016-07-14 00:38:04 +00:00
|
|
|
#define ACPI_WAKEPAGES 1
|
2012-06-09 00:37:26 +00:00
|
|
|
|
2012-06-13 22:53:56 +00:00
|
|
|
#define WAKECODE_FIXUP(offset, type, val) do { \
|
2009-03-17 00:48:11 +00:00
|
|
|
type *addr; \
|
2016-07-14 00:38:04 +00:00
|
|
|
addr = (type *)(sc->acpi_wakeaddr + (offset)); \
|
2009-03-17 00:48:11 +00:00
|
|
|
*addr = val; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
static void
|
|
|
|
acpi_stop_beep(void *arg)
|
|
|
|
{
|
2012-02-15 22:49:25 +00:00
|
|
|
|
2012-02-16 22:28:17 +00:00
|
|
|
if (acpi_resume_beep != 0)
|
|
|
|
timer_spkr_release();
|
2009-03-17 00:48:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef SMP
|
|
|
|
static int
|
|
|
|
acpi_wakeup_ap(struct acpi_softc *sc, int cpu)
|
|
|
|
{
|
2014-09-06 15:23:28 +00:00
|
|
|
struct pcb *pcb;
|
2016-07-14 00:38:04 +00:00
|
|
|
int vector = (sc->acpi_wakephys >> 12) & 0xff;
|
2009-03-17 00:48:11 +00:00
|
|
|
int apic_id = cpu_apic_ids[cpu];
|
|
|
|
int ms;
|
|
|
|
|
2014-09-06 15:23:28 +00:00
|
|
|
pcb = &susppcbs[cpu]->sp_pcb;
|
|
|
|
WAKECODE_FIXUP(wakeup_pcb, struct pcb *, pcb);
|
|
|
|
WAKECODE_FIXUP(wakeup_gdt, uint16_t, pcb->pcb_gdt.rd_limit);
|
|
|
|
WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t, pcb->pcb_gdt.rd_base);
|
2009-03-17 00:48:11 +00:00
|
|
|
|
2012-06-12 00:14:54 +00:00
|
|
|
ipi_startup(apic_id, vector);
|
2009-03-17 00:48:11 +00:00
|
|
|
|
2012-06-09 00:37:26 +00:00
|
|
|
/* Wait up to 5 seconds for it to resume. */
|
2009-03-17 00:48:11 +00:00
|
|
|
for (ms = 0; ms < 5000; ms++) {
|
2012-06-09 00:37:26 +00:00
|
|
|
if (!CPU_ISSET(cpu, &suspended_cpus))
|
2009-03-17 00:48:11 +00:00
|
|
|
return (1); /* return SUCCESS */
|
|
|
|
DELAY(1000);
|
|
|
|
}
|
|
|
|
return (0); /* return FAILURE */
|
|
|
|
}
|
|
|
|
|
|
|
|
#define WARMBOOT_TARGET 0
|
i386 4/4G split.
The change makes the user and kernel address spaces on i386
independent, giving each almost the full 4G of usable virtual addresses
except for one PDE at top used for trampoline and per-CPU trampoline
stacks, and system structures that must be always mapped, namely IDT,
GDT, common TSS and LDT, and process-private TSS and LDT if allocated.
By using 1:1 mapping for the kernel text and data, it appeared
possible to eliminate assembler part of the locore.S which bootstraps
initial page table and KPTmap. The code is rewritten in C and moved
into the pmap_cold(). The comment in vmparam.h explains the KVA
layout.
There is no PCID mechanism available in protected mode, so each
kernel/user switch forth and back completely flushes the TLB, except
for the trampoline PTD region. The TLB invalidations for userspace
becomes trivial, because IPI handlers switch page tables. On the other
hand, context switches no longer need to reload %cr3.
copyout(9) was rewritten to use vm_fault_quick_hold(). An issue for
new copyout(9) is compatibility with wiring user buffers around sysctl
handlers. This explains two kind of locks for copyout ptes and
accounting of the vslock() calls. The vm_fault_quick_hold() AKA slow
path, is only tried after the 'fast path' failed, which temporary
changes mapping to the userspace and copies the data to/from small
per-cpu buffer in the trampoline. If a page fault occurs during the
copy, it is short-circuit by exception.s to not even reach C code.
The change was motivated by the need to implement the Meltdown
mitigation, but instead of KPTI the full split is done. The i386
architecture already shows the sizing problems, in particular, it is
impossible to link clang and lld with debugging. I expect that the
issues due to the virtual address space limits would only exaggerate
and the split gives more liveness to the platform.
Tested by: pho
Discussed with: bde
Sponsored by: The FreeBSD Foundation
MFC after: 1 month
Differential revision: https://reviews.freebsd.org/D14633
2018-04-13 20:30:49 +00:00
|
|
|
#define WARMBOOT_OFF (PMAP_MAP_LOW + 0x0467)
|
|
|
|
#define WARMBOOT_SEG (PMAP_MAP_LOW + 0x0469)
|
2009-03-17 00:48:11 +00:00
|
|
|
|
|
|
|
#define CMOS_REG (0x70)
|
|
|
|
#define CMOS_DATA (0x71)
|
|
|
|
#define BIOS_RESET (0x0f)
|
|
|
|
#define BIOS_WARM (0x0a)
|
|
|
|
|
|
|
|
static void
|
2012-06-01 19:19:04 +00:00
|
|
|
acpi_wakeup_cpus(struct acpi_softc *sc)
|
2009-03-17 00:48:11 +00:00
|
|
|
{
|
|
|
|
uint32_t mpbioswarmvec;
|
|
|
|
int cpu;
|
|
|
|
u_char mpbiosreason;
|
|
|
|
|
2021-09-12 22:24:33 +03:00
|
|
|
/* save the current value of the warm-start vector */
|
|
|
|
mpbioswarmvec = *((uint32_t *)WARMBOOT_OFF);
|
|
|
|
outb(CMOS_REG, BIOS_RESET);
|
|
|
|
mpbiosreason = inb(CMOS_DATA);
|
|
|
|
|
|
|
|
/* setup a vector to our boot code */
|
|
|
|
*((volatile u_short *)WARMBOOT_OFF) = WARMBOOT_TARGET;
|
|
|
|
*((volatile u_short *)WARMBOOT_SEG) = sc->acpi_wakephys >> 4;
|
|
|
|
outb(CMOS_REG, BIOS_RESET);
|
|
|
|
outb(CMOS_DATA, BIOS_WARM); /* 'warm-start' */
|
2009-03-17 00:48:11 +00:00
|
|
|
|
|
|
|
/* Wake up each AP. */
|
|
|
|
for (cpu = 1; cpu < mp_ncpus; cpu++) {
|
2012-06-01 19:19:04 +00:00
|
|
|
if (!CPU_ISSET(cpu, &suspcpus))
|
2009-03-17 00:48:11 +00:00
|
|
|
continue;
|
|
|
|
if (acpi_wakeup_ap(sc, cpu) == 0) {
|
|
|
|
/* restore the warmstart vector */
|
|
|
|
*(uint32_t *)WARMBOOT_OFF = mpbioswarmvec;
|
|
|
|
panic("acpi_wakeup: failed to resume AP #%d (PHY #%d)",
|
|
|
|
cpu, cpu_apic_ids[cpu]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-18 13:53:22 +00:00
|
|
|
/*
|
|
|
|
* Remove the identity mapping of low memory for all CPUs and sync
|
|
|
|
* the TLB for the BSP. The APs are now spinning in
|
|
|
|
* cpususpend_handler() and we will release them soon. Then each
|
|
|
|
* will invalidate its TLB.
|
|
|
|
*/
|
i386: Merge PAE and non-PAE pmaps into same kernel.
Effectively all i386 kernels now have two pmaps compiled in: one
managing PAE pagetables, and another non-PAE. The implementation is
selected at cold time depending on the CPU features. The vm_paddr_t is
always 64bit now. As result, nx bit can be used on all capable CPUs.
Option PAE only affects the bus_addr_t: it is still 32bit for non-PAE
configs, for drivers compatibility. Kernel layout, esp. max kernel
address, low memory PDEs and max user address (same as trampoline
start) are now same for PAE and for non-PAE regardless of the type of
page tables used.
Non-PAE kernel (when using PAE pagetables) can handle physical memory
up to 24G now, larger memory requires re-tuning the KVA consumers and
instead the code caps the maximum at 24G. Unfortunately, a lot of
drivers do not use busdma(9) properly so by default even 4G barrier is
not easy. There are two tunables added: hw.above4g_allow and
hw.above24g_allow, the first one is kept enabled for now to evaluate
the status on HEAD, second is only for dev use.
i386 now creates three freelists if there is any memory above 4G, to
allow proper bounce pages allocation. Also, VM_KMEM_SIZE_SCALE changed
from 3 to 1.
The PAE_TABLES kernel config option is retired.
In collaboarion with: pho
Discussed with: emaste
Reviewed by: markj
MFC after: 2 weeks
Sponsored by: The FreeBSD Foundation
Differential revision: https://reviews.freebsd.org/D18894
2019-01-30 02:07:13 +00:00
|
|
|
pmap_remap_lowptdi(false);
|
2017-12-18 13:53:22 +00:00
|
|
|
|
2021-09-12 22:24:33 +03:00
|
|
|
/* restore the warmstart vector */
|
|
|
|
*(uint32_t *)WARMBOOT_OFF = mpbioswarmvec;
|
2009-03-17 00:48:11 +00:00
|
|
|
|
2021-09-12 22:24:33 +03:00
|
|
|
outb(CMOS_REG, BIOS_RESET);
|
|
|
|
outb(CMOS_DATA, mpbiosreason);
|
2009-03-17 00:48:11 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-07-20 06:07:34 +00:00
|
|
|
int
|
|
|
|
acpi_sleep_machdep(struct acpi_softc *sc, int state)
|
|
|
|
{
|
2009-03-17 00:48:11 +00:00
|
|
|
ACPI_STATUS status;
|
2014-09-06 15:23:28 +00:00
|
|
|
struct pcb *pcb;
|
2009-03-17 00:48:11 +00:00
|
|
|
|
|
|
|
if (sc->acpi_wakeaddr == 0ul)
|
2012-06-01 15:26:32 +00:00
|
|
|
return (-1); /* couldn't alloc wake memory */
|
2009-03-17 00:48:11 +00:00
|
|
|
|
|
|
|
#ifdef SMP
|
2012-06-01 15:26:32 +00:00
|
|
|
suspcpus = all_cpus;
|
|
|
|
CPU_CLR(PCPU_GET(cpuid), &suspcpus);
|
2009-03-17 00:48:11 +00:00
|
|
|
#endif
|
|
|
|
|
2012-02-16 22:28:17 +00:00
|
|
|
if (acpi_resume_beep != 0)
|
|
|
|
timer_spkr_acquire();
|
2012-02-15 22:49:25 +00:00
|
|
|
|
2016-07-14 00:38:04 +00:00
|
|
|
AcpiSetFirmwareWakingVector(sc->acpi_wakephys, 0);
|
2009-03-17 00:48:11 +00:00
|
|
|
|
|
|
|
intr_suspend();
|
|
|
|
|
2014-09-06 15:23:28 +00:00
|
|
|
pcb = &susppcbs[0]->sp_pcb;
|
|
|
|
if (savectx(pcb)) {
|
2014-11-02 22:58:30 +00:00
|
|
|
npxsuspend(susppcbs[0]->sp_fpususpend);
|
2009-03-17 00:48:11 +00:00
|
|
|
#ifdef SMP
|
2012-06-01 19:19:04 +00:00
|
|
|
if (!CPU_EMPTY(&suspcpus) && suspend_cpus(suspcpus) == 0) {
|
Commit the support for removing cpumask_t and replacing it directly with
cpuset_t objects.
That is going to offer the underlying support for a simple bump of
MAXCPU and then support for number of cpus > 32 (as it is today).
Right now, cpumask_t is an int, 32 bits on all our supported architecture.
cpumask_t on the other side is implemented as an array of longs, and
easilly extendible by definition.
The architectures touched by this commit are the following:
- amd64
- i386
- pc98
- arm
- ia64
- XEN
while the others are still missing.
Userland is believed to be fully converted with the changes contained
here.
Some technical notes:
- This commit may be considered an ABI nop for all the architectures
different from amd64 and ia64 (and sparc64 in the future)
- per-cpu members, which are now converted to cpuset_t, needs to be
accessed avoiding migration, because the size of cpuset_t should be
considered unknown
- size of cpuset_t objects is different from kernel and userland (this is
primirally done in order to leave some more space in userland to cope
with KBI extensions). If you need to access kernel cpuset_t from the
userland please refer to example in this patch on how to do that
correctly (kgdb may be a good source, for example).
- Support for other architectures is going to be added soon
- Only MAXCPU for amd64 is bumped now
The patch has been tested by sbruno and Nicholas Esborn on opteron
4 x 12 pack CPUs. More testing on big SMP is expected to came soon.
pluknet tested the patch with his 8-ways on both amd64 and i386.
Tested by: pluknet, sbruno, gianni, Nicholas Esborn
Reviewed by: jeff, jhb, sbruno
2011-05-05 14:39:14 +00:00
|
|
|
device_printf(sc->acpi_dev, "Failed to suspend APs\n");
|
2012-06-01 15:26:32 +00:00
|
|
|
return (0); /* couldn't sleep */
|
2009-03-17 00:48:11 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-02-16 22:28:17 +00:00
|
|
|
WAKECODE_FIXUP(resume_beep, uint8_t, (acpi_resume_beep != 0));
|
2009-03-23 22:35:30 +00:00
|
|
|
WAKECODE_FIXUP(reset_video, uint8_t, (acpi_reset_video != 0));
|
2009-03-17 00:48:11 +00:00
|
|
|
|
2019-02-07 02:09:34 +00:00
|
|
|
if ((amd_feature & AMDID_NX) != 0)
|
|
|
|
WAKECODE_FIXUP(wakeup_efer, uint64_t, rdmsr(MSR_EFER));
|
2014-09-06 15:23:28 +00:00
|
|
|
WAKECODE_FIXUP(wakeup_cr4, register_t, pcb->pcb_cr4);
|
|
|
|
WAKECODE_FIXUP(wakeup_pcb, struct pcb *, pcb);
|
|
|
|
WAKECODE_FIXUP(wakeup_gdt, uint16_t, pcb->pcb_gdt.rd_limit);
|
|
|
|
WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t, pcb->pcb_gdt.rd_base);
|
2009-03-17 00:48:11 +00:00
|
|
|
|
2017-12-18 13:53:22 +00:00
|
|
|
/*
|
|
|
|
* Map some low memory with virt == phys for ACPI wakecode
|
|
|
|
* to use to jump to high memory after enabling paging. This
|
|
|
|
* is the same as for similar jump in locore, except the
|
|
|
|
* jump is a single instruction, and we know its address
|
|
|
|
* more precisely so only need a single PTD, and we have to
|
|
|
|
* be careful to use the kernel map (PTD[0] is for curthread
|
|
|
|
* which may be a user thread in deprecated APIs).
|
|
|
|
*/
|
i386: Merge PAE and non-PAE pmaps into same kernel.
Effectively all i386 kernels now have two pmaps compiled in: one
managing PAE pagetables, and another non-PAE. The implementation is
selected at cold time depending on the CPU features. The vm_paddr_t is
always 64bit now. As result, nx bit can be used on all capable CPUs.
Option PAE only affects the bus_addr_t: it is still 32bit for non-PAE
configs, for drivers compatibility. Kernel layout, esp. max kernel
address, low memory PDEs and max user address (same as trampoline
start) are now same for PAE and for non-PAE regardless of the type of
page tables used.
Non-PAE kernel (when using PAE pagetables) can handle physical memory
up to 24G now, larger memory requires re-tuning the KVA consumers and
instead the code caps the maximum at 24G. Unfortunately, a lot of
drivers do not use busdma(9) properly so by default even 4G barrier is
not easy. There are two tunables added: hw.above4g_allow and
hw.above24g_allow, the first one is kept enabled for now to evaluate
the status on HEAD, second is only for dev use.
i386 now creates three freelists if there is any memory above 4G, to
allow proper bounce pages allocation. Also, VM_KMEM_SIZE_SCALE changed
from 3 to 1.
The PAE_TABLES kernel config option is retired.
In collaboarion with: pho
Discussed with: emaste
Reviewed by: markj
MFC after: 2 weeks
Sponsored by: The FreeBSD Foundation
Differential revision: https://reviews.freebsd.org/D18894
2019-01-30 02:07:13 +00:00
|
|
|
pmap_remap_lowptdi(true);
|
2017-12-18 13:53:22 +00:00
|
|
|
|
2009-03-17 00:48:11 +00:00
|
|
|
/* Call ACPICA to enter the desired sleep state */
|
|
|
|
if (state == ACPI_STATE_S4 && sc->acpi_s4bios)
|
|
|
|
status = AcpiEnterSleepStateS4bios();
|
|
|
|
else
|
2012-08-16 20:54:52 +00:00
|
|
|
status = AcpiEnterSleepState(state);
|
2012-06-01 21:33:33 +00:00
|
|
|
if (ACPI_FAILURE(status)) {
|
2009-03-17 00:48:11 +00:00
|
|
|
device_printf(sc->acpi_dev,
|
|
|
|
"AcpiEnterSleepState failed - %s\n",
|
|
|
|
AcpiFormatException(status));
|
2012-06-01 15:26:32 +00:00
|
|
|
return (0); /* couldn't sleep */
|
2009-03-17 00:48:11 +00:00
|
|
|
}
|
|
|
|
|
2018-05-03 19:00:50 +00:00
|
|
|
if (acpi_susp_bounce)
|
|
|
|
resumectx(pcb);
|
|
|
|
|
2009-03-17 00:48:11 +00:00
|
|
|
for (;;)
|
|
|
|
ia32_pause();
|
2014-08-30 17:48:38 +00:00
|
|
|
} else {
|
2018-05-29 16:16:24 +00:00
|
|
|
/*
|
|
|
|
* Re-initialize console hardware as soon as possibe.
|
|
|
|
* No console output (e.g. printf) is allowed before
|
|
|
|
* this point.
|
|
|
|
*/
|
|
|
|
cnresume();
|
2014-11-02 22:58:30 +00:00
|
|
|
npxresume(susppcbs[0]->sp_fpususpend);
|
2009-03-17 00:48:11 +00:00
|
|
|
}
|
|
|
|
|
2012-06-01 15:26:32 +00:00
|
|
|
return (1); /* wakeup successfully */
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-06-01 17:07:52 +00:00
|
|
|
acpi_wakeup_machdep(struct acpi_softc *sc, int state, int sleep_result,
|
|
|
|
int intr_enabled)
|
2012-06-01 15:26:32 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
if (sleep_result == -1)
|
|
|
|
return (sleep_result);
|
|
|
|
|
2012-06-01 17:07:52 +00:00
|
|
|
if (!intr_enabled) {
|
2012-06-01 15:26:32 +00:00
|
|
|
/* Wakeup MD procedures in interrupt disabled context */
|
|
|
|
if (sleep_result == 1) {
|
2018-08-13 17:13:09 +00:00
|
|
|
ucode_reload();
|
2012-06-01 15:26:32 +00:00
|
|
|
pmap_init_pat();
|
|
|
|
initializecpu();
|
|
|
|
PCPU_SET(switchtime, 0);
|
|
|
|
PCPU_SET(switchticks, ticks);
|
2015-02-20 19:42:26 +00:00
|
|
|
#ifdef DEV_APIC
|
2015-02-16 21:56:19 +00:00
|
|
|
lapic_xapic_mode();
|
2015-02-20 19:42:26 +00:00
|
|
|
#endif
|
2009-03-17 00:48:11 +00:00
|
|
|
#ifdef SMP
|
2012-06-01 15:26:32 +00:00
|
|
|
if (!CPU_EMPTY(&suspcpus))
|
2012-06-01 19:19:04 +00:00
|
|
|
acpi_wakeup_cpus(sc);
|
2009-03-17 00:48:11 +00:00
|
|
|
#endif
|
2012-06-01 15:26:32 +00:00
|
|
|
}
|
2009-03-17 00:48:11 +00:00
|
|
|
|
2012-06-01 15:26:32 +00:00
|
|
|
#ifdef SMP
|
|
|
|
if (!CPU_EMPTY(&suspcpus))
|
Use resume_cpus() instead of restart_cpus() to resume from ACPI suspension.
restart_cpus() worked well enough by accident. Before this set of fixes,
resume_cpus() used the same cpuset (started_cpus, meaning CPUs directed to
restart) as restart_cpus(). resume_cpus() waited for the wrong cpuset
(stopped_cpus) to become empty, but since mixtures of stopped and suspended
CPUs are not close to working, stopped_cpus must be empty when resuming so
the wait is null -- restart_cpus just allows the other CPUs to restart and
returns without waiting.
Fix resume_cpus() to wait on a non-wrong cpuset for the ACPI case, and
add further kludges to try to keep it working for the XEN case. It
was only used for XEN. It waited on suspended_cpus. This works for
XEN. However, for ACPI, resuming is a 2-step process. ACPI has already
woken up the other CPUs and removed them from suspended_cpus. This
fix records the move by putting them in a new cpuset resuming_cpus.
Waiting on suspended_cpus would give the same null wait as waiting on
stopped_cpus. Wait on resuming_cpus instead.
Add a cpuset toresume_cpus to map the CPUs being told to resume to keep
this separate from the cpuset started_cpus for mapping the CPUs being told
to restart. Mixtures of stopped and suspended/resuming CPUs are still far
from working. Describe new and some old cpusets in comments.
Add further kludges to cpususpend_handler() to try to avoid breaking it
for XEN. XEN doesn't use resumectx(), so it doesn't use the second
return path for savectx(), and it goes from the suspended state directly
to the restarted state, while ACPI resume goes through the resuming state.
Enter the resuming state early for all cases so that resume_cpus can test
for being in this state and not have to worry about the intermediate
!suspended state for ACPI only.
Reviewed by: kib
2017-12-21 09:17:48 +00:00
|
|
|
resume_cpus(suspcpus);
|
2012-06-01 15:26:32 +00:00
|
|
|
#endif
|
|
|
|
mca_resume();
|
2013-09-20 05:06:03 +00:00
|
|
|
intr_resume(/*suspend_cancelled*/false);
|
2012-06-01 18:18:48 +00:00
|
|
|
|
2015-06-18 23:14:45 +00:00
|
|
|
AcpiSetFirmwareWakingVector(0, 0);
|
2012-06-01 15:26:32 +00:00
|
|
|
} else {
|
|
|
|
/* Wakeup MD procedures in interrupt enabled context */
|
|
|
|
if (sleep_result == 1 && mem_range_softc.mr_op != NULL &&
|
|
|
|
mem_range_softc.mr_op->reinit != NULL)
|
|
|
|
mem_range_softc.mr_op->reinit(&mem_range_softc);
|
|
|
|
}
|
2009-03-17 00:48:11 +00:00
|
|
|
|
2012-06-01 15:26:32 +00:00
|
|
|
return (sleep_result);
|
2009-03-17 00:48:11 +00:00
|
|
|
}
|
|
|
|
|
2009-10-08 17:41:53 +00:00
|
|
|
static void *
|
2016-07-14 00:38:04 +00:00
|
|
|
acpi_alloc_wakeup_handler(void *wakepages[ACPI_WAKEPAGES])
|
2009-03-17 00:48:11 +00:00
|
|
|
{
|
2009-11-04 22:39:18 +00:00
|
|
|
int i;
|
2009-03-17 00:48:11 +00:00
|
|
|
|
2016-07-14 00:38:04 +00:00
|
|
|
memset(wakepages, 0, ACPI_WAKEPAGES * sizeof(*wakepages));
|
|
|
|
|
2009-03-17 00:48:11 +00:00
|
|
|
/*
|
|
|
|
* Specify the region for our wakeup code. We want it in the low 1 MB
|
2009-10-08 17:41:53 +00:00
|
|
|
* region, excluding real mode IVT (0-0x3ff), BDA (0x400-0x4ff), EBDA
|
|
|
|
* (less than 128KB, below 0xa0000, must be excluded by SMAP and DSDT),
|
|
|
|
* and ROM area (0xa0000 and above). The temporary page tables must be
|
|
|
|
* page-aligned.
|
2009-03-17 00:48:11 +00:00
|
|
|
*/
|
2016-07-14 00:38:04 +00:00
|
|
|
for (i = 0; i < ACPI_WAKEPAGES; i++) {
|
2019-02-07 02:09:34 +00:00
|
|
|
wakepages[i] = contigmalloc(PAGE_SIZE, M_DEVBUF,
|
2021-09-12 22:24:33 +03:00
|
|
|
M_NOWAIT | M_EXEC, 0x500, 0xa0000, PAGE_SIZE, 0ul);
|
2016-07-14 00:38:04 +00:00
|
|
|
if (wakepages[i] == NULL) {
|
|
|
|
printf("%s: can't alloc wake memory\n", __func__);
|
|
|
|
goto freepages;
|
|
|
|
}
|
2009-03-17 00:48:11 +00:00
|
|
|
}
|
2012-02-16 22:28:17 +00:00
|
|
|
if (EVENTHANDLER_REGISTER(power_resume, acpi_stop_beep, NULL,
|
|
|
|
EVENTHANDLER_PRI_LAST) == NULL) {
|
|
|
|
printf("%s: can't register event handler\n", __func__);
|
2016-07-14 00:38:04 +00:00
|
|
|
goto freepages;
|
2012-02-16 22:28:17 +00:00
|
|
|
}
|
2010-08-02 17:35:00 +00:00
|
|
|
susppcbs = malloc(mp_ncpus * sizeof(*susppcbs), M_DEVBUF, M_WAITOK);
|
Add support for the extended FPU states on amd64, both for native
64bit and 32bit ABIs. As a side-effect, it enables AVX on capable
CPUs.
In particular:
- Query the CPU support for XSAVE, list of the supported extensions
and the required size of FPU save area. The hw.use_xsave tunable is
provided for disabling XSAVE, and hw.xsave_mask may be used to
select the enabled extensions.
- Remove the FPU save area from PCB and dynamically allocate the
(run-time sized) user save area on the top of the kernel stack,
right above the PCB. Reorganize the thread0 PCB initialization to
postpone it after BSP is queried for save area size.
- The dumppcb, stoppcbs and susppcbs now do not carry the FPU state as
well. FPU state is only useful for suspend, where it is saved in
dynamically allocated suspfpusave area.
- Use XSAVE and XRSTOR to save/restore FPU state, if supported and
enabled.
- Define new mcontext_t flag _MC_HASFPXSTATE, indicating that
mcontext_t has a valid pointer to out-of-struct extended FPU
state. Signal handlers are supplied with stack-allocated fpu
state. The sigreturn(2) and setcontext(2) syscall honour the flag,
allowing the signal handlers to inspect and manipilate extended
state in the interrupted context.
- The getcontext(2) never returns extended state, since there is no
place in the fixed-sized mcontext_t to place variable-sized save
area. And, since mcontext_t is embedded into ucontext_t, makes it
impossible to fix in a reasonable way. Instead of extending
getcontext(2) syscall, provide a sysarch(2) facility to query
extended FPU state.
- Add ptrace(2) support for getting and setting extended state; while
there, implement missed PT_I386_{GET,SET}XMMREGS for 32bit binaries.
- Change fpu_kern KPI to not expose struct fpu_kern_ctx layout to
consumers, making it opaque. Internally, struct fpu_kern_ctx now
contains a space for the extended state. Convert in-kernel consumers
of fpu_kern KPI both on i386 and amd64.
First version of the support for AVX was submitted by Tim Bird
<tim.bird am sony com> on behalf of Sony. This version was written
from scratch.
Tested by: pho (previous version), Yamagi Burmeister <lists yamagi org>
MFC after: 1 month
2012-01-21 17:45:27 +00:00
|
|
|
for (i = 0; i < mp_ncpus; i++) {
|
2010-08-02 17:35:00 +00:00
|
|
|
susppcbs[i] = malloc(sizeof(**susppcbs), M_DEVBUF, M_WAITOK);
|
2014-09-06 15:23:28 +00:00
|
|
|
susppcbs[i]->sp_fpususpend = alloc_fpusave(M_WAITOK);
|
Add support for the extended FPU states on amd64, both for native
64bit and 32bit ABIs. As a side-effect, it enables AVX on capable
CPUs.
In particular:
- Query the CPU support for XSAVE, list of the supported extensions
and the required size of FPU save area. The hw.use_xsave tunable is
provided for disabling XSAVE, and hw.xsave_mask may be used to
select the enabled extensions.
- Remove the FPU save area from PCB and dynamically allocate the
(run-time sized) user save area on the top of the kernel stack,
right above the PCB. Reorganize the thread0 PCB initialization to
postpone it after BSP is queried for save area size.
- The dumppcb, stoppcbs and susppcbs now do not carry the FPU state as
well. FPU state is only useful for suspend, where it is saved in
dynamically allocated suspfpusave area.
- Use XSAVE and XRSTOR to save/restore FPU state, if supported and
enabled.
- Define new mcontext_t flag _MC_HASFPXSTATE, indicating that
mcontext_t has a valid pointer to out-of-struct extended FPU
state. Signal handlers are supplied with stack-allocated fpu
state. The sigreturn(2) and setcontext(2) syscall honour the flag,
allowing the signal handlers to inspect and manipilate extended
state in the interrupted context.
- The getcontext(2) never returns extended state, since there is no
place in the fixed-sized mcontext_t to place variable-sized save
area. And, since mcontext_t is embedded into ucontext_t, makes it
impossible to fix in a reasonable way. Instead of extending
getcontext(2) syscall, provide a sysarch(2) facility to query
extended FPU state.
- Add ptrace(2) support for getting and setting extended state; while
there, implement missed PT_I386_{GET,SET}XMMREGS for 32bit binaries.
- Change fpu_kern KPI to not expose struct fpu_kern_ctx layout to
consumers, making it opaque. Internally, struct fpu_kern_ctx now
contains a space for the extended state. Convert in-kernel consumers
of fpu_kern KPI both on i386 and amd64.
First version of the support for AVX was submitted by Tim Bird
<tim.bird am sony com> on behalf of Sony. This version was written
from scratch.
Tested by: pho (previous version), Yamagi Burmeister <lists yamagi org>
MFC after: 1 month
2012-01-21 17:45:27 +00:00
|
|
|
}
|
2001-07-20 06:07:34 +00:00
|
|
|
|
2016-07-14 00:38:04 +00:00
|
|
|
return (wakepages);
|
|
|
|
|
|
|
|
freepages:
|
|
|
|
for (i = 0; i < ACPI_WAKEPAGES; i++)
|
|
|
|
if (wakepages[i] != NULL)
|
|
|
|
contigfree(wakepages[i], PAGE_SIZE, M_DEVBUF);
|
|
|
|
return (NULL);
|
2009-10-08 17:41:53 +00:00
|
|
|
}
|
2009-03-17 00:48:11 +00:00
|
|
|
|
2001-07-20 06:07:34 +00:00
|
|
|
void
|
|
|
|
acpi_install_wakeup_handler(struct acpi_softc *sc)
|
|
|
|
{
|
2021-09-11 21:26:51 +03:00
|
|
|
static void *wakeaddr;
|
|
|
|
void *wakepages[ACPI_WAKEPAGES];
|
2009-03-17 00:48:11 +00:00
|
|
|
|
2009-10-08 17:41:53 +00:00
|
|
|
if (wakeaddr != NULL)
|
|
|
|
return;
|
|
|
|
|
2016-07-14 00:38:04 +00:00
|
|
|
if (acpi_alloc_wakeup_handler(wakepages) == NULL)
|
2009-03-17 00:48:11 +00:00
|
|
|
return;
|
|
|
|
|
2016-07-14 00:38:04 +00:00
|
|
|
wakeaddr = wakepages[0];
|
2009-10-08 17:41:53 +00:00
|
|
|
sc->acpi_wakeaddr = (vm_offset_t)wakeaddr;
|
|
|
|
sc->acpi_wakephys = vtophys(wakeaddr);
|
2009-03-17 00:48:11 +00:00
|
|
|
|
2016-07-14 00:38:04 +00:00
|
|
|
bcopy(wakecode, (void *)sc->acpi_wakeaddr, sizeof(wakecode));
|
2009-03-17 00:48:11 +00:00
|
|
|
|
2012-06-09 00:37:26 +00:00
|
|
|
/* Patch GDT base address, ljmp targets. */
|
2009-03-17 00:48:11 +00:00
|
|
|
WAKECODE_FIXUP((bootgdtdesc + 2), uint32_t,
|
2016-07-14 00:38:04 +00:00
|
|
|
sc->acpi_wakephys + bootgdt);
|
2009-03-17 00:48:11 +00:00
|
|
|
WAKECODE_FIXUP((wakeup_sw32 + 2), uint32_t,
|
2016-07-14 00:38:04 +00:00
|
|
|
sc->acpi_wakephys + wakeup_32);
|
2009-03-17 00:48:11 +00:00
|
|
|
|
|
|
|
/* Save pointers to some global data. */
|
2012-06-09 00:37:26 +00:00
|
|
|
WAKECODE_FIXUP(wakeup_ret, void *, resumectx);
|
i386: Merge PAE and non-PAE pmaps into same kernel.
Effectively all i386 kernels now have two pmaps compiled in: one
managing PAE pagetables, and another non-PAE. The implementation is
selected at cold time depending on the CPU features. The vm_paddr_t is
always 64bit now. As result, nx bit can be used on all capable CPUs.
Option PAE only affects the bus_addr_t: it is still 32bit for non-PAE
configs, for drivers compatibility. Kernel layout, esp. max kernel
address, low memory PDEs and max user address (same as trampoline
start) are now same for PAE and for non-PAE regardless of the type of
page tables used.
Non-PAE kernel (when using PAE pagetables) can handle physical memory
up to 24G now, larger memory requires re-tuning the KVA consumers and
instead the code caps the maximum at 24G. Unfortunately, a lot of
drivers do not use busdma(9) properly so by default even 4G barrier is
not easy. There are two tunables added: hw.above4g_allow and
hw.above24g_allow, the first one is kept enabled for now to evaluate
the status on HEAD, second is only for dev use.
i386 now creates three freelists if there is any memory above 4G, to
allow proper bounce pages allocation. Also, VM_KMEM_SIZE_SCALE changed
from 3 to 1.
The PAE_TABLES kernel config option is retired.
In collaboarion with: pho
Discussed with: emaste
Reviewed by: markj
MFC after: 2 weeks
Sponsored by: The FreeBSD Foundation
Differential revision: https://reviews.freebsd.org/D18894
2019-01-30 02:07:13 +00:00
|
|
|
WAKECODE_FIXUP(wakeup_cr3, register_t, pmap_get_kcr3());
|
2009-03-17 00:48:11 +00:00
|
|
|
|
|
|
|
if (bootverbose)
|
2012-06-09 00:37:26 +00:00
|
|
|
device_printf(sc->acpi_dev, "wakeup code va %#jx pa %#jx\n",
|
|
|
|
(uintmax_t)sc->acpi_wakeaddr, (uintmax_t)sc->acpi_wakephys);
|
2001-07-20 06:07:34 +00:00
|
|
|
}
|