-/* $OpenBSD: pmap.c,v 1.148 2021/09/14 16:14:50 kettenis Exp $ */
+/* $OpenBSD: pmap.c,v 1.149 2022/02/01 08:38:53 guenther Exp $ */
/* $NetBSD: pmap.c,v 1.3 2003/05/08 18:13:13 thorpej Exp $ */
/*
if (pmap == pmap_kernel())
npte |= pg_g_kern;
- PTE_BASE[pl1_i(va)] = npte; /* zap! */
-
/*
- * If we changed anything other than modified/used bits,
- * flush the TLB. (is this overkill?)
+ * If the old entry wasn't valid, we can just update it and
+ * go. If it was valid, and this isn't a read->write
+ * transition, then we can safely just update it and flush
+ * any old TLB entries.
+ *
+ * If it _was_ valid and this _is_ a read->write transition,
+ * then this could be a CoW resolution and we need to make
+ * sure no CPU can see the new writable mapping while another
+ * still has the old mapping in its TLB, so insert a correct
+ * but unwritable mapping, flush any old TLB entries, then
+ * make it writable.
*/
- if (pmap_valid_entry(opte)) {
+ if (! pmap_valid_entry(opte)) {
+ PTE_BASE[pl1_i(va)] = npte;
+ } else if ((opte | (npte ^ PG_RW)) & PG_RW) {
+ /* previously writable or not making writable */
+ PTE_BASE[pl1_i(va)] = npte;
if (nocache && (opte & PG_N) == 0)
wbinvd_on_all_cpus();
pmap_tlb_shootpage(pmap, va, shootself);
+ } else {
+ PTE_BASE[pl1_i(va)] = npte ^ PG_RW;
+ if (nocache && (opte & PG_N) == 0) /* XXX impossible? */
+ wbinvd_on_all_cpus();
+ pmap_tlb_shootpage(pmap, va, shootself);
+ pmap_tlb_shootwait();
+ PTE_BASE[pl1_i(va)] = npte;
}
pmap_unmap_ptes(pmap, scr3);
-/* $OpenBSD: pmap.h,v 1.78 2021/06/18 06:17:28 guenther Exp $ */
+/* $OpenBSD: pmap.h,v 1.79 2022/02/01 08:38:53 guenther Exp $ */
/* $NetBSD: pmap.h,v 1.1 2003/04/26 18:39:46 fvdl Exp $ */
/*
#define pmap_unmap_direct(va) PHYS_TO_VM_PAGE(PMAP_DIRECT_UNMAP(va))
#define __HAVE_PMAP_DIRECT
+#define __HAVE_PMAP_MPSAFE_ENTER_COW
#endif /* _KERNEL && !_LOCORE */
-/* $OpenBSD: uvm_fault.c,v 1.124 2021/12/28 13:16:28 mpi Exp $ */
+/* $OpenBSD: uvm_fault.c,v 1.125 2022/02/01 08:38:53 guenther Exp $ */
/* $NetBSD: uvm_fault.c,v 1.51 2000/08/06 00:22:53 thorpej Exp $ */
/*
/* deref: can not drop to zero here by defn! */
oanon->an_ref--;
+#ifndef __HAVE_PMAP_MPSAFE_ENTER_COW
+ /*
+ * If there are multiple threads, either uvm or the
+ * pmap has to make sure no threads see the old RO
+ * mapping once any have seen the new RW mapping.
+ * uvm does it by inserting the new mapping RO and
+ * letting it fault again.
+ */
+ if (P_HASSIBLING(curproc))
+ flt->enter_prot &= ~PROT_WRITE;
+#endif
+
/*
* note: anon is _not_ locked, but we have the sole references
* to in from amap.