Clean up amd64 suspend/resume code.

- Allocate memory for wakeup code after ACPI bus is attached.  The early
memory allocation hack was inherited from i386 but amd64 does not need it.
- Exclude real mode IVT and BDA explicitly.  Improve comments about memory
allocation and reason for the exclusions.  It is a no-op in reality, though.
- Remove an unnecessary CLD from wakeup code and re-align.
This commit is contained in:
Jung-uk Kim 2009-10-08 17:41:53 +00:00
parent c217b20ef6
commit a7e2341e20
3 changed files with 35 additions and 33 deletions

View File

@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/sysctl.h>
#include <vm/vm.h>
#include <vm/pmap.h>
@ -511,7 +512,6 @@ acpi_machdep_init(device_t dev)
sc->acpi_clone = apm_create_clone(sc->acpi_dev_t, sc);
clone_setup(&apm_clones);
EVENTHANDLER_REGISTER(dev_clone, apm_clone, 0, 1000);
acpi_install_wakeup_handler(sc);
if (intr_model != ACPI_INTR_PIC)
acpi_SetIntrModel(intr_model);
@ -801,13 +801,20 @@ nexus_acpi_probe(device_t dev)
static int
nexus_acpi_attach(device_t dev)
{
device_t acpi_dev;
int error;
nexus_init_resources();
bus_generic_probe(dev);
if (BUS_ADD_CHILD(dev, 10, "acpi", 0) == NULL)
acpi_dev = BUS_ADD_CHILD(dev, 10, "acpi", 0);
if (acpi_dev == NULL)
panic("failed to add acpi0 device");
return (bus_generic_attach(dev));
error = bus_generic_attach(dev);
if (error == 0)
acpi_install_wakeup_handler(device_get_softc(acpi_dev));
return (error);
}
static device_method_t nexus_acpi_methods[] = {

View File

@ -54,18 +54,17 @@
.data /* So we can modify it */
ALIGN_TEXT
wakeup_start:
.code16
wakeup_start:
/*
* Set up segment registers for real mode, a small stack for
* any calls we make, and clear any flags.
*/
cli /* make sure no interrupts */
cld
mov %cs, %ax /* copy %cs to %ds. Remember these */
mov %ax, %ds /* are offsets rather than selectors */
mov %ax, %ss
movw $PAGE_SIZE - 8, %sp
movw $PAGE_SIZE, %sp
xorw %ax, %ax
pushw %ax
popfw
@ -129,6 +128,7 @@ wakeup_sw32:
/*
* At this point, we are running in 32 bit legacy protected mode.
*/
ALIGN_TEXT
.code32
wakeup_32:

View File

@ -31,13 +31,11 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/memrange.h>
#include <sys/smp.h>
#include <sys/types.h>
#include <vm/vm.h>
#include <vm/pmap.h>
@ -46,11 +44,11 @@ __FBSDID("$FreeBSD$");
#include <machine/pcb.h>
#include <machine/pmap.h>
#include <machine/specialreg.h>
#include <machine/vmparam.h>
#ifdef SMP
#include <machine/apicreg.h>
#include <machine/smp.h>
#include <machine/vmparam.h>
#endif
#include <contrib/dev/acpica/include/acpi.h>
@ -63,10 +61,6 @@ __FBSDID("$FreeBSD$");
/* Make sure the code is less than a page and leave room for the stack. */
CTASSERT(sizeof(wakecode) < PAGE_SIZE - 1024);
#ifndef _SYS_CDEFS_H_
#error this file needs sys/cdefs.h as a prerequisite
#endif
extern int acpi_resume_beep;
extern int acpi_reset_video;
@ -79,7 +73,7 @@ static struct xpcb *stopxpcbs;
int acpi_restorecpu(struct xpcb *, vm_offset_t);
int acpi_savecpu(struct xpcb *);
static void acpi_alloc_wakeup_handler(void);
static void *acpi_alloc_wakeup_handler(void);
static void acpi_stop_beep(void *);
#ifdef SMP
@ -322,49 +316,50 @@ out:
return (ret);
}
static vm_offset_t acpi_wakeaddr;
static void
static void *
acpi_alloc_wakeup_handler(void)
{
void *wakeaddr;
if (!cold)
return;
/*
* Specify the region for our wakeup code. We want it in the low 1 MB
* region, excluding video memory and above (0xa0000). We ask for
* it to be page-aligned, just to be safe.
* 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.
*/
wakeaddr = contigmalloc(4 * PAGE_SIZE, M_DEVBUF, M_NOWAIT, 0, 0x9ffff,
PAGE_SIZE, 0ul);
wakeaddr = contigmalloc(4 * PAGE_SIZE, M_DEVBUF, M_NOWAIT, 0x500,
0xa0000, PAGE_SIZE, 0ul);
if (wakeaddr == NULL) {
printf("%s: can't alloc wake memory\n", __func__);
return;
return (NULL);
}
stopxpcbs = malloc(mp_ncpus * sizeof(*stopxpcbs), M_DEVBUF, M_NOWAIT);
if (stopxpcbs == NULL) {
contigfree(wakeaddr, 4 * PAGE_SIZE, M_DEVBUF);
printf("%s: can't alloc CPU state memory\n", __func__);
return;
return (NULL);
}
acpi_wakeaddr = (vm_offset_t)wakeaddr;
}
SYSINIT(acpiwakeup, SI_SUB_KMEM, SI_ORDER_ANY, acpi_alloc_wakeup_handler, 0);
return (wakeaddr);
}
void
acpi_install_wakeup_handler(struct acpi_softc *sc)
{
static void *wakeaddr = NULL;
uint64_t *pt4, *pt3, *pt2;
int i;
if (acpi_wakeaddr == 0ul)
if (wakeaddr != NULL)
return;
sc->acpi_wakeaddr = acpi_wakeaddr;
sc->acpi_wakephys = vtophys(acpi_wakeaddr);
wakeaddr = acpi_alloc_wakeup_handler();
if (wakeaddr == NULL)
return;
sc->acpi_wakeaddr = (vm_offset_t)wakeaddr;
sc->acpi_wakephys = vtophys(wakeaddr);
bcopy(wakecode, (void *)WAKECODE_VADDR(sc), sizeof(wakecode));
@ -390,7 +385,7 @@ acpi_install_wakeup_handler(struct acpi_softc *sc)
WAKECODE_FIXUP(wakeup_sfmask, uint64_t, rdmsr(MSR_SF_MASK));
/* Build temporary page tables below realmode code. */
pt4 = (uint64_t *)acpi_wakeaddr;
pt4 = wakeaddr;
pt3 = pt4 + (PAGE_SIZE) / sizeof(uint64_t);
pt2 = pt3 + (PAGE_SIZE) / sizeof(uint64_t);