Changeset View
Changeset View
Standalone View
Standalone View
sys/x86/acpica/acpi_wakeup.c
Show First 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | |||||
static void acpi_stop_beep(void *); | static void acpi_stop_beep(void *); | ||||
#ifdef SMP | #ifdef SMP | ||||
static int acpi_wakeup_ap(struct acpi_softc *, int); | static int acpi_wakeup_ap(struct acpi_softc *, int); | ||||
static void acpi_wakeup_cpus(struct acpi_softc *); | static void acpi_wakeup_cpus(struct acpi_softc *); | ||||
#endif | #endif | ||||
#ifdef __amd64__ | #ifdef __amd64__ | ||||
#define ACPI_WAKEPAGES 5 | #define ACPI_WAKEPAGES 8 | ||||
#else | #else | ||||
#define ACPI_WAKEPAGES 1 | #define ACPI_WAKEPAGES 1 | ||||
#endif | #endif | ||||
#define WAKECODE_FIXUP(offset, type, val) do { \ | #define WAKECODE_FIXUP(offset, type, val) do { \ | ||||
type *addr; \ | type *addr; \ | ||||
addr = (type *)(sc->acpi_wakeaddr + (offset)); \ | addr = (type *)(sc->acpi_wakeaddr + (offset)); \ | ||||
*addr = val; \ | *addr = val; \ | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
acpi_wakeup_cpus(struct acpi_softc *sc) | acpi_wakeup_cpus(struct acpi_softc *sc) | ||||
{ | { | ||||
uint32_t mpbioswarmvec; | uint32_t mpbioswarmvec; | ||||
int cpu; | int cpu; | ||||
u_char mpbiosreason; | u_char mpbiosreason; | ||||
#ifdef __amd64__ | |||||
if (!efi_boot) { | |||||
#endif | |||||
/* save the current value of the warm-start vector */ | /* save the current value of the warm-start vector */ | ||||
mpbioswarmvec = *((uint32_t *)WARMBOOT_OFF); | mpbioswarmvec = *((uint32_t *)WARMBOOT_OFF); | ||||
outb(CMOS_REG, BIOS_RESET); | outb(CMOS_REG, BIOS_RESET); | ||||
mpbiosreason = inb(CMOS_DATA); | mpbiosreason = inb(CMOS_DATA); | ||||
/* setup a vector to our boot code */ | /* setup a vector to our boot code */ | ||||
*((volatile u_short *)WARMBOOT_OFF) = WARMBOOT_TARGET; | *((volatile u_short *)WARMBOOT_OFF) = WARMBOOT_TARGET; | ||||
*((volatile u_short *)WARMBOOT_SEG) = sc->acpi_wakephys >> 4; | *((volatile u_short *)WARMBOOT_SEG) = sc->acpi_wakephys >> 4; | ||||
outb(CMOS_REG, BIOS_RESET); | outb(CMOS_REG, BIOS_RESET); | ||||
outb(CMOS_DATA, BIOS_WARM); /* 'warm-start' */ | outb(CMOS_DATA, BIOS_WARM); /* 'warm-start' */ | ||||
#ifdef __amd64__ | |||||
} | |||||
#endif | |||||
/* Wake up each AP. */ | /* Wake up each AP. */ | ||||
for (cpu = 1; cpu < mp_ncpus; cpu++) { | for (cpu = 1; cpu < mp_ncpus; cpu++) { | ||||
if (!CPU_ISSET(cpu, &suspcpus)) | if (!CPU_ISSET(cpu, &suspcpus)) | ||||
continue; | continue; | ||||
if (acpi_wakeup_ap(sc, cpu) == 0) { | if (acpi_wakeup_ap(sc, cpu) == 0) { | ||||
/* restore the warmstart vector */ | /* restore the warmstart vector */ | ||||
*(uint32_t *)WARMBOOT_OFF = mpbioswarmvec; | *(uint32_t *)WARMBOOT_OFF = mpbioswarmvec; | ||||
panic("acpi_wakeup: failed to resume AP #%d (PHY #%d)", | panic("acpi_wakeup: failed to resume AP #%d (PHY #%d)", | ||||
cpu, cpu_apic_ids[cpu]); | cpu, cpu_apic_ids[cpu]); | ||||
} | } | ||||
} | } | ||||
#ifdef __i386__ | #ifdef __i386__ | ||||
/* | /* | ||||
* Remove the identity mapping of low memory for all CPUs and sync | * Remove the identity mapping of low memory for all CPUs and sync | ||||
* the TLB for the BSP. The APs are now spinning in | * the TLB for the BSP. The APs are now spinning in | ||||
* cpususpend_handler() and we will release them soon. Then each | * cpususpend_handler() and we will release them soon. Then each | ||||
* will invalidate its TLB. | * will invalidate its TLB. | ||||
*/ | */ | ||||
pmap_remap_lowptdi(false); | pmap_remap_lowptdi(false); | ||||
#endif | #endif | ||||
#ifdef __amd64__ | |||||
if (!efi_boot) { | |||||
#endif | |||||
/* restore the warmstart vector */ | /* restore the warmstart vector */ | ||||
*(uint32_t *)WARMBOOT_OFF = mpbioswarmvec; | *(uint32_t *)WARMBOOT_OFF = mpbioswarmvec; | ||||
outb(CMOS_REG, BIOS_RESET); | outb(CMOS_REG, BIOS_RESET); | ||||
outb(CMOS_DATA, mpbiosreason); | outb(CMOS_DATA, mpbiosreason); | ||||
#ifdef __amd64__ | |||||
} | } | ||||
#endif | #endif | ||||
} | |||||
#endif | |||||
int | int | ||||
acpi_sleep_machdep(struct acpi_softc *sc, int state) | acpi_sleep_machdep(struct acpi_softc *sc, int state) | ||||
{ | { | ||||
ACPI_STATUS status; | ACPI_STATUS status; | ||||
struct pcb *pcb; | struct pcb *pcb; | ||||
#ifdef __amd64__ | #ifdef __amd64__ | ||||
struct pcpu *pc; | struct pcpu *pc; | ||||
▲ Show 20 Lines • Show All 191 Lines • ▼ Show 20 Lines | for (i = 0; i < ACPI_WAKEPAGES; i++) | ||||
if (wakepages[i] != NULL) | if (wakepages[i] != NULL) | ||||
contigfree(wakepages[i], PAGE_SIZE, M_DEVBUF); | contigfree(wakepages[i], PAGE_SIZE, M_DEVBUF); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
void | void | ||||
acpi_install_wakeup_handler(struct acpi_softc *sc) | acpi_install_wakeup_handler(struct acpi_softc *sc) | ||||
{ | { | ||||
static void *wakeaddr; | static void *wakeaddr; | ||||
void *wakepages[ACPI_WAKEPAGES]; | void *wakepages[ACPI_WAKEPAGES]; | ||||
#ifdef __amd64__ | #ifdef __amd64__ | ||||
uint64_t *pt5, *pt4, *pt3, *pt2; | uint64_t *pt5, *pt4, *pt3, *pt2_0, *pt2_1, *pt2_2, *pt2_3; | ||||
vm_paddr_t pt5pa, pt4pa, pt3pa, pt2pa; | vm_paddr_t pt5pa, pt4pa, pt3pa, pt2_0pa, pt2_1pa, pt2_2pa, pt2_3pa; | ||||
int i; | int i; | ||||
#endif | #endif | ||||
if (wakeaddr != NULL) | if (wakeaddr != NULL) | ||||
return; | return; | ||||
if (acpi_alloc_wakeup_handler(wakepages) == NULL) | if (acpi_alloc_wakeup_handler(wakepages) == NULL) | ||||
return; | return; | ||||
wakeaddr = wakepages[0]; | wakeaddr = wakepages[0]; | ||||
sc->acpi_wakeaddr = (vm_offset_t)wakeaddr; | sc->acpi_wakeaddr = (vm_offset_t)wakeaddr; | ||||
sc->acpi_wakephys = vtophys(wakeaddr); | sc->acpi_wakephys = vtophys(wakeaddr); | ||||
#ifdef __amd64__ | #ifdef __amd64__ | ||||
if (la57) { | if (la57) { | ||||
pt5 = wakepages[4]; | pt5 = wakepages[7]; | ||||
pt5pa = vtophys(pt5); | pt5pa = vtophys(pt5); | ||||
} | } | ||||
pt4 = wakepages[1]; | pt4 = wakepages[1]; | ||||
pt3 = wakepages[2]; | pt3 = wakepages[2]; | ||||
pt2 = wakepages[3]; | pt2_0 = wakepages[3]; | ||||
pt2_1 = wakepages[4]; | |||||
pt2_2 = wakepages[5]; | |||||
pt2_3 = wakepages[6]; | |||||
pt4pa = vtophys(pt4); | pt4pa = vtophys(pt4); | ||||
pt3pa = vtophys(pt3); | pt3pa = vtophys(pt3); | ||||
pt2pa = vtophys(pt2); | pt2_0pa = vtophys(pt2_0); | ||||
pt2_1pa = vtophys(pt2_1); | |||||
pt2_2pa = vtophys(pt2_2); | |||||
pt2_3pa = vtophys(pt2_3); | |||||
#endif | #endif | ||||
bcopy(wakecode, (void *)sc->acpi_wakeaddr, sizeof(wakecode)); | bcopy(wakecode, (void *)sc->acpi_wakeaddr, sizeof(wakecode)); | ||||
/* Patch GDT base address, ljmp targets. */ | /* Patch GDT base address, ljmp targets. */ | ||||
WAKECODE_FIXUP((bootgdtdesc + 2), uint32_t, | WAKECODE_FIXUP((bootgdtdesc + 2), uint32_t, | ||||
sc->acpi_wakephys + bootgdt); | sc->acpi_wakephys + bootgdt); | ||||
WAKECODE_FIXUP((wakeup_sw32 + 2), uint32_t, | WAKECODE_FIXUP((wakeup_sw32 + 2), uint32_t, | ||||
sc->acpi_wakephys + wakeup_32); | sc->acpi_wakephys + wakeup_32); | ||||
#ifdef __amd64__ | #ifdef __amd64__ | ||||
WAKECODE_FIXUP((wakeup_sw64 + 1), uint32_t, | WAKECODE_FIXUP((wakeup_sw64 + 1), uint32_t, | ||||
sc->acpi_wakephys + wakeup_64); | sc->acpi_wakephys + wakeup_64); | ||||
WAKECODE_FIXUP(wakeup_pagetables, uint32_t, la57 ? (pt5pa | 0x1) : | WAKECODE_FIXUP(wakeup_pagetables, uint32_t, la57 ? (pt5pa | 0x1) : | ||||
pt4pa); | pt4pa); | ||||
#endif | #endif | ||||
/* Save pointers to some global data. */ | /* Save pointers to some global data. */ | ||||
WAKECODE_FIXUP(wakeup_ret, void *, resumectx); | WAKECODE_FIXUP(wakeup_ret, void *, resumectx); | ||||
#ifndef __amd64__ | #ifndef __amd64__ | ||||
WAKECODE_FIXUP(wakeup_cr3, register_t, pmap_get_kcr3()); | WAKECODE_FIXUP(wakeup_cr3, register_t, pmap_get_kcr3()); | ||||
#else /* __amd64__ */ | #else /* __amd64__ */ | ||||
/* Create the initial 1GB replicated page tables */ | /* Create 1:1 mapping for the low 4G */ | ||||
for (i = 0; i < NPTEPG; i++) { | |||||
if (la57) { | if (la57) { | ||||
pt5[i] = (uint64_t)pt4pa; | bcopy(kernel_pmap->pm_pmltop, pt5, PAGE_SIZE); | ||||
pt5[i] |= PG_V | PG_RW | PG_U; | pt5[0] = (uint64_t)pt4pa; | ||||
pt5[0] |= PG_V | PG_RW | PG_U; | |||||
} else { | |||||
bcopy(kernel_pmap->pm_pmltop, pt4, PAGE_SIZE); | |||||
} | } | ||||
/* | pt4[0] = (uint64_t)pt3pa; | ||||
* Each slot of the level 4 pages points | pt4[0] |= PG_V | PG_RW | PG_U; | ||||
* to the same level 3 page | |||||
*/ | |||||
pt4[i] = (uint64_t)pt3pa; | |||||
pt4[i] |= PG_V | PG_RW | PG_U; | |||||
/* | pt3[0] = (uint64_t)pt2_0pa; | ||||
* Each slot of the level 3 pages points | pt3[0] |= PG_V | PG_RW | PG_U; | ||||
* to the same level 2 page | pt3[1] = (uint64_t)pt2_1pa; | ||||
*/ | pt3[1] |= PG_V | PG_RW | PG_U; | ||||
pt3[i] = (uint64_t)pt2pa; | pt3[2] = (uint64_t)pt2_2pa; | ||||
pt3[i] |= PG_V | PG_RW | PG_U; | pt3[2] |= PG_V | PG_RW | PG_U; | ||||
pt3[3] = (uint64_t)pt2_3pa; | |||||
pt3[3] |= PG_V | PG_RW | PG_U; | |||||
/* The level 2 page slots are mapped with 2MB pages for 1GB. */ | for (i = 0; i < NPDEPG; i++) { | ||||
pt2[i] = i * NBPDR; | pt2_0[i] = (pd_entry_t)i * NBPDR; | ||||
pt2[i] |= PG_V | PG_RW | PG_PS | PG_U; | pt2_0[i] |= PG_V | PG_RW | PG_PS | PG_U; | ||||
} | } | ||||
for (i = 0; i < NPDEPG; i++) { | |||||
pt2_1[i] = (pd_entry_t)NBPDP + i * NBPDR; | |||||
pt2_1[i] |= PG_V | PG_RW | PG_PS | PG_U; | |||||
} | |||||
for (i = 0; i < NPDEPG; i++) { | |||||
pt2_2[i] = (pd_entry_t)2 * NBPDP + i * NBPDR; | |||||
pt2_2[i] |= PG_V | PG_RW | PG_PS | PG_U; | |||||
} | |||||
for (i = 0; i < NPDEPG; i++) { | |||||
pt2_3[i] = (pd_entry_t)3 * NBPDP + i * NBPDR; | |||||
pt2_3[i] |= PG_V | PG_RW | PG_PS | PG_U; | |||||
markj: Why do we set PG_U here? | |||||
kibAuthorUnsubmitted Done Inline ActionsI do not think there is a reason now. It might be there was some reason before, if e.g. vm86 mode was used on the wakeup path [Or any other trampoline from real mode to final protection mode, we are consistent to set PG_U on all trampoline ptes, I believe] So it probably was moved from i386 to amd64 and live there since. I have another change to the acpi_wakeup.c in pipe, after that I might look into coalescing code that creates page table for low 4G 1:1. kib: I do not think there is a reason now. It might be there was some reason before, if e.g. vm86… | |||||
} | |||||
#endif /* !__amd64__ */ | #endif /* !__amd64__ */ | ||||
if (bootverbose) | if (bootverbose) | ||||
device_printf(sc->acpi_dev, "wakeup code va %#jx pa %#jx\n", | device_printf(sc->acpi_dev, "wakeup code va %#jx pa %#jx\n", | ||||
(uintmax_t)sc->acpi_wakeaddr, (uintmax_t)sc->acpi_wakephys); | (uintmax_t)sc->acpi_wakeaddr, (uintmax_t)sc->acpi_wakephys); | ||||
} | } |
Why do we set PG_U here?