summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/i386/i386/locore.s74
-rw-r--r--sys/x86/acpica/acpi_wakeup.c24
-rw-r--r--sys/x86/x86/mp_x86.c5
3 files changed, 60 insertions, 43 deletions
diff --git a/sys/i386/i386/locore.s b/sys/i386/i386/locore.s
index 04b82dfbece5..ab3f79ffdcf6 100644
--- a/sys/i386/i386/locore.s
+++ b/sys/i386/i386/locore.s
@@ -241,22 +241,30 @@ NON_GPROF_ENTRY(btext)
#if defined(PAE) || defined(PAE_TABLES)
movl R(IdlePDPT), %eax
movl %eax, %cr3
- movl %cr4, %eax
- orl $CR4_PAE, %eax
- movl %eax, %cr4
+ movl %cr4, %edx
+ orl $CR4_PAE, %edx
+ movl %edx, %cr4
#else
movl R(IdlePTD), %eax
movl %eax,%cr3 /* load ptd addr into mmu */
#endif
- movl %cr0,%eax /* get control word */
- orl $CR0_PE|CR0_PG,%eax /* enable paging */
- movl %eax,%cr0 /* and let's page NOW! */
+ movl %cr0,%edx /* get control word */
+ orl $CR0_PE|CR0_PG,%edx /* enable paging */
+ movl %edx,%cr0 /* and let's page NOW! */
pushl $begin /* jump to high virtualized address */
ret
-/* now running relocated at KERNBASE where the system is linked to run */
begin:
+ /*
+ * Now running relocated at KERNBASE where the system is linked to run.
+ *
+ * Remove the lowest part of the double mapping of low memory to get
+ * some null pointer checks.
+ */
+ movl $0,PTD
+ movl %eax,%cr3 /* invalidate TLB */
+
/* set up bootstrap stack */
movl proc0kstack,%eax /* location of in-kernel stack */
@@ -725,14 +733,15 @@ no_kernend:
/*
* Initialize page table pages mapping physical address zero through the
- * end of the kernel. All of the page table entries allow read and write
- * access. Write access to the first physical page is required by bios32
- * calls, and write access to the first 1 MB of physical memory is required
- * by ACPI for implementing suspend and resume. We do this even
- * if we've enabled PSE above, we'll just switch the corresponding kernel
- * PDEs before we turn on paging.
+ * (physical) end of the kernel. Many of these pages must be reserved,
+ * and we reserve them all and map them linearly for convenience. We do
+ * this even if we've enabled PSE above; we'll just switch the corresponding
+ * kernel PDEs before we turn on paging.
*
* XXX: We waste some pages here in the PSE case!
+ *
+ * This and all other page table entries allow read and write access for
+ * various reasons. Kernel mappings never have any access restrictions.
*/
xorl %eax, %eax
movl R(KERNend),%ecx
@@ -784,42 +793,21 @@ no_kernend:
/*
* Create an identity mapping for low physical memory, including the kernel.
- * The part of this mapping given by the first PDE (for the first 4 MB or 2
- * MB of physical memory)
- * becomes a permanent part of the kernel's address space. The rest of this
- * mapping is destroyed in pmap_bootstrap(). Ordinarily, the same page table
- * pages are shared by the identity mapping and the kernel's native mapping.
- * However, the permanent identity mapping cannot contain PG_G mappings.
- * Thus, if the (physical) kernel overlaps the permanent identity mapping
- * (and PG_G is enabled), the
- * page table for the first PDE must be duplicated and not shared.
+ * This is only used to map the 2 instructions for jumping to 'begin' in
+ * locore (we map everything to avoid having to determine where these
+ * instructions are). ACPI resume will transiently restore the first PDE in
+ * this mapping (and depend on this PDE's page table created here not being
+ * destroyed). See pmap_bootstrap() for more details.
*
- * N.B. Due to errata concerning large pages and physical address zero,
- * a PG_PS mapping is not used.
+ * Note: There are errata concerning large pages and physical address zero,
+ * so a PG_PS mapping should not be used for PDE 0. Our double mapping
+ * avoids this automatically by not using PG_PS for PDE #KPDI so that PAT
+ * bits can be set at the page level for i/o pages below 1 MB.
*/
movl R(KPTphys), %eax
xorl %ebx, %ebx
movl $NKPT, %ecx
fillkpt(R(IdlePTD), $PG_RW)
-#if KERNLOAD < (1 << PDRSHIFT)
- testl $PG_G, R(pgeflag)
- jz 1f
- ALLOCPAGES(1)
- movl %esi, %eax
- movl $1, %ecx
- fillkptphys($PG_RW) /* map the new page table in std map */
- movl %esi, %edi
- movl R(IdlePTD), %eax
- movl (%eax), %esi /* top bits are 0 for PAE */
- andl $~PAGE_MASK, %esi
- movl %edi, (%eax)
- orl $PG_V | PG_RW, (%eax) /* finish writing new PTD[0] */
- movl $PAGE_SIZE, %ecx
- cld
- rep
- movsb
-1:
-#endif
/*
* Install PDEs for PTs covering enough kva to bootstrap. Then for the PSE
diff --git a/sys/x86/acpica/acpi_wakeup.c b/sys/x86/acpica/acpi_wakeup.c
index a4c5683aee8e..853ead4a90a7 100644
--- a/sys/x86/acpica/acpi_wakeup.c
+++ b/sys/x86/acpica/acpi_wakeup.c
@@ -179,6 +179,17 @@ acpi_wakeup_cpus(struct acpi_softc *sc)
}
}
+#ifdef __i386__
+ /*
+ * Remove the identity mapping of low memory for all CPUs and sync
+ * the TLB for the BSP. The APs are now spinning in
+ * cpususpend_handler() and we will release them soon. Then each
+ * will invalidate its TLB.
+ */
+ kernel_pmap->pm_pdir[0] = 0;
+ invltlb_glob();
+#endif
+
/* restore the warmstart vector */
*(uint32_t *)WARMBOOT_OFF = mpbioswarmvec;
@@ -235,6 +246,19 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
WAKECODE_FIXUP(wakeup_gdt, uint16_t, pcb->pcb_gdt.rd_limit);
WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t, pcb->pcb_gdt.rd_base);
+#ifdef __i386__
+ /*
+ * Map some low memory with virt == phys for ACPI wakecode
+ * to use to jump to high memory after enabling paging. This
+ * is the same as for similar jump in locore, except the
+ * jump is a single instruction, and we know its address
+ * more precisely so only need a single PTD, and we have to
+ * be careful to use the kernel map (PTD[0] is for curthread
+ * which may be a user thread in deprecated APIs).
+ */
+ kernel_pmap->pm_pdir[0] = PTD[KPTDI];
+#endif
+
/* Call ACPICA to enter the desired sleep state */
if (state == ACPI_STATE_S4 && sc->acpi_s4bios)
status = AcpiEnterSleepStateS4bios();
diff --git a/sys/x86/x86/mp_x86.c b/sys/x86/x86/mp_x86.c
index c14b181913b2..bc2f3526369d 100644
--- a/sys/x86/x86/mp_x86.c
+++ b/sys/x86/x86/mp_x86.c
@@ -1398,6 +1398,11 @@ cpususpend_handler(void)
while (!CPU_ISSET(cpu, &started_cpus))
ia32_pause();
+#ifdef __i386__
+ /* Finish removing the identity mapping of low memory for this AP. */
+ invltlb_glob();
+#endif
+
if (cpu_ops.cpu_resume)
cpu_ops.cpu_resume();
#ifdef __amd64__