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
This commit is contained in:
parent
d22ff6e6a2
commit
f76b5ab6cc
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=343851
@ -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:
|
||||
|
@ -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_WAKEPAGES])
|
||||
* 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;
|
||||
|
Loading…
Reference in New Issue
Block a user