Ensure that resume path on amd64 only accesses page tables for normal

operation after processor is configured to allow all required
features.

In particular, NX must be enabled in EFER, otherwise load of page
table element with nx bit set causes reserved bit page fault.  Since
malloc uses direct mapping for small allocations, in particular for
the suspension pcbs, and DMAP is nx after r316767, this commit tripped
fault on resume path.

Restore complete state of EFER while wakeup code is still executing
with custom page table, before calling resumectx, instead of trying to
guess which features might be needed before resumectx restored EFER on
its own.

Bisected and tested by:	trasz
Sponsored by:	The FreeBSD Foundation
MFC after:	2 weeks
This commit is contained in:
Konstantin Belousov 2017-05-15 20:52:43 +00:00
parent f701bdc59e
commit bd101a6648
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=318318
3 changed files with 10 additions and 5 deletions

View File

@ -156,11 +156,12 @@ wakeup_32:
/*
* Enable EFER.LME so that we get long mode when all the prereqs are
* in place. In this case, it turns on when CR0_PG is finally enabled.
* Pick up a few other EFER bits that we'll use need we're here.
* Also it picks up a few other EFER bits that we'll use need we're
* here, like SYSCALL and NX enable.
*/
movl $MSR_EFER, %ecx
rdmsr
orl $EFER_LME | EFER_SCE, %eax
movl wakeup_efer - wakeup_start(%ebx), %eax
movl wakeup_efer + 4 - wakeup_start(%ebx), %edx
wrmsr
/*
@ -276,6 +277,8 @@ wakeup_pcb:
.quad 0
wakeup_ret:
.quad 0
wakeup_efer:
.quad 0
wakeup_gdt:
.word 0
.quad 0

View File

@ -396,7 +396,7 @@ ENTRY(resumectx)
movl 4 + PCB_KGSBASE(%rdi),%edx
wrmsr
/* Restore EFER. */
/* Restore EFER one more time. */
movl $MSR_EFER,%ecx
movl PCB_EFER(%rdi),%eax
wrmsr

View File

@ -223,7 +223,9 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
WAKECODE_FIXUP(resume_beep, uint8_t, (acpi_resume_beep != 0));
WAKECODE_FIXUP(reset_video, uint8_t, (acpi_reset_video != 0));
#ifndef __amd64__
#ifdef __amd64__
WAKECODE_FIXUP(wakeup_efer, uint64_t, rdmsr(MSR_EFER));
#else
WAKECODE_FIXUP(wakeup_cr4, register_t, pcb->pcb_cr4);
#endif
WAKECODE_FIXUP(wakeup_pcb, struct pcb *, pcb);