diff options
author | markj <markj@FreeBSD.org> | 2017-02-03 01:21:56 +0000 |
---|---|---|
committer | markj <markj@FreeBSD.org> | 2017-02-03 01:21:56 +0000 |
commit | 0148019e01ccc71ae3c8ceeee77c0b299724b046 (patch) | |
tree | c39e998477a91d110233036788df7f018efeb65d | |
parent | db7e6e1f39aa131ac58e8b008ac615682ea72b84 (diff) | |
download | FreeBSD-src-0148019e01ccc71ae3c8ceeee77c0b299724b046.zip FreeBSD-src-0148019e01ccc71ae3c8ceeee77c0b299724b046.tar.gz |
MFC r302793:
Allow ACPI wakeup code and page tables to be stored in non-contiguous pages.
-rw-r--r-- | sys/x86/acpica/acpi_wakeup.c | 87 |
1 files changed, 48 insertions, 39 deletions
diff --git a/sys/x86/acpica/acpi_wakeup.c b/sys/x86/acpica/acpi_wakeup.c index 869f2eb..d551b02 100644 --- a/sys/x86/acpica/acpi_wakeup.c +++ b/sys/x86/acpica/acpi_wakeup.c @@ -88,7 +88,7 @@ static cpuset_t suspcpus; static struct susppcb **susppcbs; #endif -static void *acpi_alloc_wakeup_handler(void); +static void *acpi_alloc_wakeup_handler(void **); static void acpi_stop_beep(void *); #ifdef SMP @@ -97,18 +97,14 @@ static void acpi_wakeup_cpus(struct acpi_softc *); #endif #ifdef __amd64__ -#define ACPI_PAGETABLES 3 +#define ACPI_WAKEPAGES 4 #else -#define ACPI_PAGETABLES 0 +#define ACPI_WAKEPAGES 1 #endif -#define WAKECODE_VADDR(sc) \ - ((sc)->acpi_wakeaddr + (ACPI_PAGETABLES * PAGE_SIZE)) -#define WAKECODE_PADDR(sc) \ - ((sc)->acpi_wakephys + (ACPI_PAGETABLES * PAGE_SIZE)) #define WAKECODE_FIXUP(offset, type, val) do { \ type *addr; \ - addr = (type *)(WAKECODE_VADDR(sc) + offset); \ + addr = (type *)(sc->acpi_wakeaddr + (offset)); \ *addr = val; \ } while (0) @@ -125,7 +121,7 @@ static int acpi_wakeup_ap(struct acpi_softc *sc, int cpu) { struct pcb *pcb; - int vector = (WAKECODE_PADDR(sc) >> 12) & 0xff; + int vector = (sc->acpi_wakephys >> 12) & 0xff; int apic_id = cpu_apic_ids[cpu]; int ms; @@ -168,7 +164,7 @@ acpi_wakeup_cpus(struct acpi_softc *sc) /* setup a vector to our boot code */ *((volatile u_short *)WARMBOOT_OFF) = WARMBOOT_TARGET; - *((volatile u_short *)WARMBOOT_SEG) = WAKECODE_PADDR(sc) >> 4; + *((volatile u_short *)WARMBOOT_SEG) = sc->acpi_wakephys >> 4; outb(CMOS_REG, BIOS_RESET); outb(CMOS_DATA, BIOS_WARM); /* 'warm-start' */ @@ -209,7 +205,7 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state) if (acpi_resume_beep != 0) timer_spkr_acquire(); - AcpiSetFirmwareWakingVector(WAKECODE_PADDR(sc), 0); + AcpiSetFirmwareWakingVector(sc->acpi_wakephys, 0); intr_suspend(); @@ -309,11 +305,12 @@ acpi_wakeup_machdep(struct acpi_softc *sc, int state, int sleep_result, } static void * -acpi_alloc_wakeup_handler(void) +acpi_alloc_wakeup_handler(void *wakepages[ACPI_WAKEPAGES]) { - void *wakeaddr; int i; + memset(wakepages, 0, ACPI_WAKEPAGES * sizeof(*wakepages)); + /* * Specify the region for our wakeup code. We want it in the low 1 MB * region, excluding real mode IVT (0-0x3ff), BDA (0x400-0x4ff), EBDA @@ -321,18 +318,18 @@ acpi_alloc_wakeup_handler(void) * and ROM area (0xa0000 and above). The temporary page tables must be * page-aligned. */ - wakeaddr = contigmalloc((ACPI_PAGETABLES + 1) * PAGE_SIZE, M_DEVBUF, - M_NOWAIT, 0x500, 0xa0000, PAGE_SIZE, 0ul); - if (wakeaddr == NULL) { - printf("%s: can't alloc wake memory\n", __func__); - return (NULL); + for (i = 0; i < ACPI_WAKEPAGES; i++) { + wakepages[i] = contigmalloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT, + 0x500, 0xa0000, PAGE_SIZE, 0ul); + if (wakepages[i] == NULL) { + printf("%s: can't alloc wake memory\n", __func__); + goto freepages; + } } if (EVENTHANDLER_REGISTER(power_resume, acpi_stop_beep, NULL, EVENTHANDLER_PRI_LAST) == NULL) { printf("%s: can't register event handler\n", __func__); - contigfree(wakeaddr, (ACPI_PAGETABLES + 1) * PAGE_SIZE, - M_DEVBUF); - return (NULL); + goto freepages; } susppcbs = malloc(mp_ncpus * sizeof(*susppcbs), M_DEVBUF, M_WAITOK); for (i = 0; i < mp_ncpus; i++) { @@ -340,39 +337,56 @@ acpi_alloc_wakeup_handler(void) susppcbs[i]->sp_fpususpend = alloc_fpusave(M_WAITOK); } - return (wakeaddr); + return (wakepages); + +freepages: + for (i = 0; i < ACPI_WAKEPAGES; i++) + if (wakepages[i] != NULL) + contigfree(wakepages[i], PAGE_SIZE, M_DEVBUF); + return (NULL); } void acpi_install_wakeup_handler(struct acpi_softc *sc) { - static void *wakeaddr = NULL; + static void *wakeaddr; + void *wakepages[ACPI_WAKEPAGES]; #ifdef __amd64__ uint64_t *pt4, *pt3, *pt2; + vm_paddr_t pt4pa, pt3pa, pt2pa; int i; #endif if (wakeaddr != NULL) return; - wakeaddr = acpi_alloc_wakeup_handler(); - if (wakeaddr == NULL) + if (acpi_alloc_wakeup_handler(wakepages) == NULL) return; + wakeaddr = wakepages[0]; sc->acpi_wakeaddr = (vm_offset_t)wakeaddr; sc->acpi_wakephys = vtophys(wakeaddr); - bcopy(wakecode, (void *)WAKECODE_VADDR(sc), sizeof(wakecode)); +#ifdef __amd64__ + pt4 = wakepages[1]; + pt3 = wakepages[2]; + pt2 = wakepages[3]; + pt4pa = vtophys(pt4); + pt3pa = vtophys(pt3); + pt2pa = vtophys(pt2); +#endif + + bcopy(wakecode, (void *)sc->acpi_wakeaddr, sizeof(wakecode)); /* Patch GDT base address, ljmp targets. */ WAKECODE_FIXUP((bootgdtdesc + 2), uint32_t, - WAKECODE_PADDR(sc) + bootgdt); + sc->acpi_wakephys + bootgdt); WAKECODE_FIXUP((wakeup_sw32 + 2), uint32_t, - WAKECODE_PADDR(sc) + wakeup_32); + sc->acpi_wakephys + wakeup_32); #ifdef __amd64__ WAKECODE_FIXUP((wakeup_sw64 + 1), uint32_t, - WAKECODE_PADDR(sc) + wakeup_64); - WAKECODE_FIXUP(wakeup_pagetables, uint32_t, sc->acpi_wakephys); + sc->acpi_wakephys + wakeup_64); + WAKECODE_FIXUP(wakeup_pagetables, uint32_t, pt4pa); #endif /* Save pointers to some global data. */ @@ -384,33 +398,28 @@ acpi_install_wakeup_handler(struct acpi_softc *sc) WAKECODE_FIXUP(wakeup_cr3, register_t, vtophys(kernel_pmap->pm_pdir)); #endif -#else - /* Build temporary page tables below realmode code. */ - pt4 = wakeaddr; - pt3 = pt4 + (PAGE_SIZE) / sizeof(uint64_t); - pt2 = pt3 + (PAGE_SIZE) / sizeof(uint64_t); - +#else /* __amd64__ */ /* Create the initial 1GB replicated page tables */ for (i = 0; i < 512; i++) { /* * Each slot of the level 4 pages points * to the same level 3 page */ - pt4[i] = (uint64_t)(sc->acpi_wakephys + PAGE_SIZE); + pt4[i] = (uint64_t)pt3pa; pt4[i] |= PG_V | PG_RW | PG_U; /* * Each slot of the level 3 pages points * to the same level 2 page */ - pt3[i] = (uint64_t)(sc->acpi_wakephys + (2 * PAGE_SIZE)); + pt3[i] = (uint64_t)pt2pa; pt3[i] |= PG_V | PG_RW | PG_U; /* The level 2 page slots are mapped with 2MB pages for 1GB. */ pt2[i] = i * (2 * 1024 * 1024); pt2[i] |= PG_V | PG_RW | PG_PS | PG_U; } -#endif +#endif /* !__amd64__ */ if (bootverbose) device_printf(sc->acpi_dev, "wakeup code va %#jx pa %#jx\n", |