kernel - Fix some rare pmap races in i386 and x86_64.
authorMatthew Dillon <dillon@apollo.backplane.com>
Mon, 22 Feb 2010 02:23:13 +0000 (18:23 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Mon, 22 Feb 2010 02:23:13 +0000 (18:23 -0800)
commitc2fb025d4cd1fc6d547f7ae973ee7b227c83bf15
treef9df1bee856b0313af3852d834c1da37acfd3e55
parent27815e470ee26a308f2225f7141835784852a489
kernel - Fix some rare pmap races in i386 and x86_64.

* Adjust pmap_inval_init() to enter a critical section and add
  a new pmap_inval_done() function which flushes and exits it.

  It was possible for an interrupt or other preemptive action to
  come along during a pmap operation and issue its own pmap operation,
  potentially leading to races which corrupt the pmap.

  This case was tested an could actually occur, though the damage (if any)
  is unknown.  x86_64 machines have had a long standing and difficult to
  reproduce bug where a program would sometimes seg-fault for no reason.
  It is unknown whether this fixes the bug or not.

* Interlock the pmap structure when invalidating pages using a bit
  in the pm_active field.

  Check for the interlock in swtch.s when switching into threads
  and print a nice warning if it occurs.

  It was possible for one cpu to initiate a pmap modifying operation
  while another switches into a thread using the pmap the first cpu
  was in the middle of modifying.  The case is extremely rare but can
  occur if the cpu doing the modifying operation receives a SMI
  interrupt, stalling it long enough for the other cpu to switch
  into the thread and resume running in userspace.

* pmap_protect() assumed no races when clearing PG_RW and PG_M due
  to the pmap_inval operations it runs.  This should in fact be
  true with the above fixes.  However, the rest of the pmap code
  uses atomic operations so adjust pmap_protect() to also use atomic
  operations.
17 files changed:
sys/platform/pc32/i386/genassym.c
sys/platform/pc32/i386/globals.s
sys/platform/pc32/i386/pmap.c
sys/platform/pc32/i386/pmap_inval.c
sys/platform/pc32/i386/swtch.s
sys/platform/pc32/include/pmap.h
sys/platform/pc32/include/pmap_inval.h
sys/platform/pc64/include/pmap.h
sys/platform/pc64/include/pmap_inval.h
sys/platform/pc64/x86_64/genassym.c
sys/platform/pc64/x86_64/global.s
sys/platform/pc64/x86_64/pmap.c
sys/platform/pc64/x86_64/pmap_inval.c
sys/platform/pc64/x86_64/swtch.s
sys/platform/vkernel/i386/genassym.c
sys/platform/vkernel/i386/global.s
sys/platform/vkernel/platform/pmap.c