Oops. Turn T_PAGEFLT back into an interrupt gate. It is *critical*

that interrupts be disabled and remain disabled until %cr2 is read.
Otherwise we can preempt and another process can fault, and by the
time we read %cr2, we see a different processes fault address.  This
Greatly Confuses vm_fault() (to say the least).  The i386 port has
got this marked as a bug workaround for a Cyrix CPU, which is what
lead me astray.  Its actually necessary for preemption, regardless
of whether Cyrix cpus had a bug or not.
This commit is contained in:
peter 2003-05-08 08:25:51 +00:00
parent 2ed5055d26
commit 5596d2cb7e
2 changed files with 10 additions and 2 deletions

View File

@ -1219,7 +1219,7 @@ hammer_time(void)
setidt(11, &IDTVEC(missing), SDT_SYSTGT, SEL_KPL, 0);
setidt(12, &IDTVEC(stk), SDT_SYSTGT, SEL_KPL, 0);
setidt(13, &IDTVEC(prot), SDT_SYSTGT, SEL_KPL, 0);
setidt(14, &IDTVEC(page), SDT_SYSTGT, SEL_KPL, 0);
setidt(14, &IDTVEC(page), SDT_SYSIGT, SEL_KPL, 0);
setidt(15, &IDTVEC(rsvd), SDT_SYSTGT, SEL_KPL, 0);
setidt(16, &IDTVEC(fpu), SDT_SYSTGT, SEL_KPL, 0);
setidt(17, &IDTVEC(align), SDT_SYSTGT, SEL_KPL, 0);

View File

@ -213,9 +213,17 @@ trap(frame)
* do the VM lookup, so just consider it a fatal trap so the
* kernel can print out a useful trap message and even get
* to the debugger.
*
* Note that T_PAGEFLT is registered as an interrupt gate. This
* is just like a trap gate, except interrupts are disabled. This
* happens to be critically important, because we could otherwise
* preempt and run another process that may cause %cr2 to be
* clobbered for something else.
*/
eva = rcr2();
if (PCPU_GET(spinlocks) != NULL)
if (PCPU_GET(spinlocks) == NULL)
enable_intr();
else
trap_fatal(&frame, eva);
}