summaryrefslogtreecommitdiffstats
path: root/sys/mips
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2010-01-26 02:26:04 +0000
committerneel <neel@FreeBSD.org>2010-01-26 02:26:04 +0000
commitc282e9faa80007004c23a815b0193d2cefad60d0 (patch)
tree2e2413e2ce5390af0080b0b0e8ae4545ba2c36f7 /sys/mips
parent5cd5dea33bd9e5836617934509e913f7c130c4d8 (diff)
downloadFreeBSD-src-c282e9faa80007004c23a815b0193d2cefad60d0.zip
FreeBSD-src-c282e9faa80007004c23a815b0193d2cefad60d0.tar.gz
Fix a problem seen when a new process was returning to userland
through fork_trampoline. This was caused because we were clearing the SR_INT_IE and setting SR_EXL bits of the status register at the same time. This meant that if an interrupt happened while this MTC0 was making its way through the pipeline the exception processing would see the status register with SR_EXL bit set. This in turn would mean that the COP_0_EXC_PC would not be updated so the return from exception would be to an incorrect address. It is easy to verify this fix by a program that forks in a loop and the child just exits: while (1) { pid_t pid = vfork(); if (pid == 0) _exit(0); if (pid != -1) waitpid(pid, NULL, 0); } Also remove two instances where we set SR_EXL bit gratuitously in exception.S. Approved by: imp (mentor)
Diffstat (limited to 'sys/mips')
-rw-r--r--sys/mips/include/cpuregs.h6
-rw-r--r--sys/mips/mips/exception.S6
-rw-r--r--sys/mips/mips/swtch.S6
3 files changed, 6 insertions, 12 deletions
diff --git a/sys/mips/include/cpuregs.h b/sys/mips/include/cpuregs.h
index e3070ba..f1f2485 100644
--- a/sys/mips/include/cpuregs.h
+++ b/sys/mips/include/cpuregs.h
@@ -106,7 +106,11 @@
#elif defined(CPU_SB1)
#define COP0_SYNC ssnop; ssnop; ssnop; ssnop; ssnop; ssnop; ssnop; ssnop; ssnop
#else
-#define COP0_SYNC /* nothing */
+/*
+ * Pick a reasonable default based on the "typical" spacing described in the
+ * "CP0 Hazards" chapter of MIPS Architecture Book Vol III.
+ */
+#define COP0_SYNC ssnop; ssnop; ssnop; ssnop; ssnop
#endif
#define COP0_HAZARD_FPUENABLE nop; nop; nop; nop;
diff --git a/sys/mips/mips/exception.S b/sys/mips/mips/exception.S
index 182ff85..fdac5e3 100644
--- a/sys/mips/mips/exception.S
+++ b/sys/mips/mips/exception.S
@@ -519,9 +519,6 @@ NNON_LEAF(MipsUserGenException, STAND_FRAME_SIZE, ra)
and t0, t0, ~(MIPS_SR_INT_IE)
mtc0 t0, COP_0_STATUS_REG
ITLBNOPFIX
- or t0, t0, SR_EXL
- mtc0 t0, COP_0_STATUS_REG # set exeption level
- ITLBNOPFIX
/*
* The use of k1 for storing the PCB pointer must be done only
@@ -751,9 +748,6 @@ NNON_LEAF(MipsUserIntr, STAND_FRAME_SIZE, ra)
and t0, t0, ~(MIPS_SR_INT_IE)
mtc0 t0, COP_0_STATUS_REG
ITLBNOPFIX
- or t0, t0, SR_EXL
- mtc0 t0, COP_0_STATUS_REG # set exeption level
- ITLBNOPFIX
GET_CPU_PCPU(k1)
lw k1, PC_CURPCB(k1)
diff --git a/sys/mips/mips/swtch.S b/sys/mips/mips/swtch.S
index bb84625..8620ab4 100644
--- a/sys/mips/mips/swtch.S
+++ b/sys/mips/mips/swtch.S
@@ -171,13 +171,9 @@ LEAF(fork_trampoline)
1:
mfc0 v0, COP_0_STATUS_REG # set exeption level bit.
- or v0, SR_EXL
and v0, ~(SR_INT_ENAB)
mtc0 v0, COP_0_STATUS_REG # set exeption level bit.
- nop
- nop
- nop
- nop
+ COP0_SYNC
.set noat
move k1, a1
RESTORE_U_PCB_REG(t0, MULLO, k1)
OpenPOWER on IntegriCloud