svn commit: r343851 - in head/sys: i386/acpica x86/acpica
Konstantin Belousov
kib at FreeBSD.org
Thu Feb 7 02:09:35 UTC 2019
Author: kib
Date: Thu Feb 7 02:09:34 2019
New Revision: 343851
URL: https://svnweb.freebsd.org/changeset/base/343851
Log:
Fix resume on i386 PAE.
It was broken before PAE/no-PAE merge, but since now PAE is the
default, resume is apparently becomes for all machines.
The corrected issues:
- the trampoline page is not mapped executable, so machine faults when
paging is on;
- MSR.EFER and %cr4 both should be loaded before paging is enabled,
otherwise paging structures are invalid (cr4.PAE and EFER.NX).
- MSR.EFER and %cr4 should be only loaded if present. I attempt to handle
this by not touching the registers if the value is zero.
There are some more bits still not quite correct, e.g. unconditional
access to %cr4 in resumectx.
Reported and debugging help by: bde
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Modified:
head/sys/i386/acpica/acpi_wakecode.S
head/sys/x86/acpica/acpi_wakeup.c
Modified: head/sys/i386/acpica/acpi_wakecode.S
==============================================================================
--- head/sys/i386/acpica/acpi_wakecode.S Thu Feb 7 02:00:23 2019 (r343850)
+++ head/sys/i386/acpica/acpi_wakecode.S Thu Feb 7 02:09:34 2019 (r343851)
@@ -143,16 +143,26 @@ wakeup_32:
mov $bootdata32 - bootgdt, %eax
mov %ax, %ds
- /* Get PCB and return address. */
- movl wakeup_pcb - wakeup_start(%ebx), %ecx
- movl wakeup_ret - wakeup_start(%ebx), %edx
-
- /* Restore CR4 and CR3. */
- movl wakeup_cr4 - wakeup_start(%ebx), %eax
+ /* Restore EFER, CR4 and CR3. */
+ movl wakeup_efer - wakeup_start(%ebx), %eax
+ movl wakeup_efer - wakeup_start + 4(%ebx), %edx
+ cmpl $0, %eax
+ jne 1f
+ cmpl $0, %edx
+ je 2f
+1: movl $MSR_EFER, %ecx
+ wrmsr
+2: movl wakeup_cr4 - wakeup_start(%ebx), %eax
+ cmpl $0, %eax
+ je 3f
mov %eax, %cr4
- movl wakeup_cr3 - wakeup_start(%ebx), %eax
+3: movl wakeup_cr3 - wakeup_start(%ebx), %eax
mov %eax, %cr3
+ /* Get PCB and return address. */
+ movl wakeup_ret - wakeup_start(%ebx), %edx
+ movl wakeup_pcb - wakeup_start(%ebx), %ecx
+
/* Enable paging. */
mov %cr0, %eax
orl $CR0_PG, %eax
@@ -187,6 +197,9 @@ bootgdtdesc:
.long bootgdt - wakeup_start /* Offset plus %ds << 4 */
ALIGN_DATA
+wakeup_efer:
+ .long 0
+ .long 0
wakeup_cr4:
.long 0
wakeup_cr3:
Modified: head/sys/x86/acpica/acpi_wakeup.c
==============================================================================
--- head/sys/x86/acpica/acpi_wakeup.c Thu Feb 7 02:00:23 2019 (r343850)
+++ head/sys/x86/acpica/acpi_wakeup.c Thu Feb 7 02:09:34 2019 (r343851)
@@ -260,6 +260,8 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
WAKECODE_FIXUP(wakeup_efer, uint64_t, rdmsr(MSR_EFER) &
~(EFER_LMA));
#else
+ if ((amd_feature & AMDID_NX) != 0)
+ WAKECODE_FIXUP(wakeup_efer, uint64_t, rdmsr(MSR_EFER));
WAKECODE_FIXUP(wakeup_cr4, register_t, pcb->pcb_cr4);
#endif
WAKECODE_FIXUP(wakeup_pcb, struct pcb *, pcb);
@@ -375,8 +377,12 @@ acpi_alloc_wakeup_handler(void *wakepages[ACPI_WAKEPAG
* page-aligned.
*/
for (i = 0; i < ACPI_WAKEPAGES; i++) {
- wakepages[i] = contigmalloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT,
- 0x500, 0xa0000, PAGE_SIZE, 0ul);
+ wakepages[i] = contigmalloc(PAGE_SIZE, M_DEVBUF,
+ M_NOWAIT
+#ifdef __i386__
+ | M_EXEC
+#endif
+ , 0x500, 0xa0000, PAGE_SIZE, 0ul);
if (wakepages[i] == NULL) {
printf("%s: can't alloc wake memory\n", __func__);
goto freepages;
More information about the svn-src-all
mailing list