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-head mailing list