From 918c66aceae53c85351ae2aef2609cefd399f792 Mon Sep 17 00:00:00 2001 From: kettenis Date: Sun, 26 Apr 2015 11:09:32 +0000 Subject: [PATCH] Disable PAE when switching to the hibernate resume pagetables. This involves a slightly conmplicated dance where we stash the PAE PDPTEs into the hibernate resume pagetables and use those before turning off PAE. Makes (un)hibernate work with the new PAE pmap. ok mlarkin@ --- sys/arch/i386/i386/acpi_wakecode.S | 18 +++++++++++++++++- sys/arch/i386/i386/hibernate_machdep.c | 14 +++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/sys/arch/i386/i386/acpi_wakecode.S b/sys/arch/i386/i386/acpi_wakecode.S index 952dc78a522..5cd7170b607 100644 --- a/sys/arch/i386/i386/acpi_wakecode.S +++ b/sys/arch/i386/i386/acpi_wakecode.S @@ -359,9 +359,25 @@ NENTRY(hibernate_activate_resume_pt_machdep) andl $(~CR4_PGE), %eax movl %eax, %cr4 + /* + * Switch to the hibernate resume pagetable if we're running + * in non-PAE mode. If we're running in PAE mode, this will + * switch to the PTPDEs we stashed into the hibernate resume + * pagetable, but continue to use the normal pagetables until we + * disable PAE below. + */ + movl $HIBERNATE_PD_PAGE, %eax + orl $0xfe0, %eax + movl %eax, %cr3 + + /* Disable PAE */ + movl %cr4, %eax + andl $(~CR4_PAE), %eax + movl %eax, %cr4 + wbinvd movl $HIBERNATE_PD_PAGE, %eax - movl %eax, %cr3 + movl %eax, %cr3 jmp 1f 1: nop diff --git a/sys/arch/i386/i386/hibernate_machdep.c b/sys/arch/i386/i386/hibernate_machdep.c index 6b2eeb5b61a..c76850d1081 100644 --- a/sys/arch/i386/i386/hibernate_machdep.c +++ b/sys/arch/i386/i386/hibernate_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hibernate_machdep.c,v 1.45 2015/04/12 18:37:53 mlarkin Exp $ */ +/* $OpenBSD: hibernate_machdep.c,v 1.46 2015/04/26 11:09:32 kettenis Exp $ */ /* * Copyright (c) 2011 Mike Larkin @@ -244,6 +244,7 @@ hibernate_populate_resume_pt(union hibernate_info *hib_info, paddr_t pa; vaddr_t kern_start_4m_va, kern_end_4m_va, page; vaddr_t piglet_start_va, piglet_end_va; + struct pmap *kpm = pmap_kernel(); /* Identity map PD, PT, and stack pages */ pmap_kenter_pa(HIBERNATE_PT_PAGE, HIBERNATE_PT_PAGE, PROT_MASK); @@ -307,6 +308,17 @@ hibernate_populate_resume_pt(union hibernate_info *hib_info, hibernate_enter_resume_mapping(page, pa, 1); } + /* + * Fill last 8 slots of the new PD with the PAE PDPTEs of the + * kernel pmap, such that we can easily switch back into + * non-PAE mode. If we're running in non-PAE mode, this will + * just fill the slots with zeroes. + */ + ((uint64_t *)HIBERNATE_PD_PAGE)[508] = kpm->pm_pdidx[0]; + ((uint64_t *)HIBERNATE_PD_PAGE)[509] = kpm->pm_pdidx[1]; + ((uint64_t *)HIBERNATE_PD_PAGE)[510] = kpm->pm_pdidx[2]; + ((uint64_t *)HIBERNATE_PD_PAGE)[511] = kpm->pm_pdidx[3]; + /* Unmap MMU pages (stack remains mapped) */ pmap_kremove(HIBERNATE_PT_PAGE, PAGE_SIZE); pmap_kremove(HIBERNATE_PD_PAGE, PAGE_SIZE); -- 2.20.1