Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144508648
D29851.1775114240.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
3 KB
Referenced Files
None
Subscribers
None
D29851.1775114240.diff
View Options
diff --git a/sys/powerpc/include/reg.h b/sys/powerpc/include/reg.h
--- a/sys/powerpc/include/reg.h
+++ b/sys/powerpc/include/reg.h
@@ -68,6 +68,11 @@
int fill_dbregs(struct thread *, struct dbreg *);
int set_dbregs(struct thread *, struct dbreg *);
+/*
+ * MD interfaces.
+ */
+void cpu_save_thread_regs(struct thread *);
+
#ifdef COMPAT_FREEBSD32
struct image_params;
diff --git a/sys/powerpc/powerpc/exec_machdep.c b/sys/powerpc/powerpc/exec_machdep.c
--- a/sys/powerpc/powerpc/exec_machdep.c
+++ b/sys/powerpc/powerpc/exec_machdep.c
@@ -570,6 +570,74 @@
cleanup_fpscr();
}
+/*
+ * Ensure the PCB has been updated in preparation for copying a thread.
+ *
+ * This is needed because normally this only happens during switching tasks,
+ * but when we are cloning a thread, we need the updated state before doing
+ * the actual copy, so the new thread inherits the current state instead of
+ * the state at the last task switch.
+ *
+ * Keep this in sync with the assembly code in cpu_switch()!
+ */
+void
+cpu_save_thread_regs(struct thread *td)
+{
+ uint32_t pcb_flags;
+ struct pcb *pcb;
+
+ KASSERT(td == curthread,
+ ("cpu_save_thread_regs: td is not curthread"));
+
+ pcb = td->td_pcb;
+
+ pcb_flags = pcb->pcb_flags;
+
+#if defined(__powerpc64__)
+ /* Are *any* FSCR flags in use? */
+ if (pcb_flags & PCB_CFSCR) {
+ pcb->pcb_fscr = mfspr(SPR_FSCR);
+
+ if (pcb->pcb_fscr & FSCR_EBB) {
+ pcb->pcb_ebb.ebbhr = mfspr(SPR_EBBHR);
+ pcb->pcb_ebb.ebbrr = mfspr(SPR_EBBRR);
+ pcb->pcb_ebb.bescr = mfspr(SPR_BESCR);
+ }
+ if (pcb->pcb_fscr & FSCR_LM) {
+ pcb->pcb_lm.lmrr = mfspr(SPR_LMRR);
+ pcb->pcb_lm.lmser = mfspr(SPR_LMSER);
+ }
+ if (pcb->pcb_fscr & FSCR_TAR)
+ pcb->pcb_tar = mfspr(SPR_TAR);
+ }
+
+ /*
+ * This is outside of the PCB_CFSCR check because it can be set
+ * independently when running on POWER7/POWER8.
+ */
+ if (pcb_flags & PCB_CDSCR)
+ pcb->pcb_dscr = mfspr(SPR_DSCRP);
+#endif
+
+#if defined(__SPE__)
+ /*
+ * On E500v2, single-precision scalar instructions and access to
+ * SPEFSCR may be used without PSL_VEC turned on, as long as they
+ * limit themselves to the low word of the registers.
+ *
+ * As such, we need to unconditionally save SPEFSCR, even though
+ * it is also updated in save_vec_nodrop().
+ */
+ pcb->pcb_vec.vscr = mfspr(SPR_SPEFSCR);
+#endif
+
+ if (pcb_flags & PCB_FPU)
+ save_fpu_nodrop(td);
+
+ if (pcb_flags & PCB_VEC)
+ save_vec_nodrop(td);
+}
+
/*
* Set set up registers on exec.
*/
@@ -1028,6 +1096,10 @@
struct trapframe *tf;
struct callframe *cf;
+ /* Ensure td0 pcb is up to date. */
+ if (td == curthread)
+ cpu_save_thread_regs(td0);
+
pcb2 = td->td_pcb;
/* Copy the upcall pcb */
diff --git a/sys/powerpc/powerpc/swtch32.S b/sys/powerpc/powerpc/swtch32.S
--- a/sys/powerpc/powerpc/swtch32.S
+++ b/sys/powerpc/powerpc/swtch32.S
@@ -104,6 +104,8 @@
mr %r16,%r5 /* and the new lock */
mr %r17,%r6 /* and the PCB */
+ /* Keep this next section in sync with cpu_save_thread_regs()! */
+
lwz %r18,PCB_FLAGS(%r17)
/* Save FPU context if needed */
andi. %r7, %r18, PCB_FPU
diff --git a/sys/powerpc/powerpc/swtch64.S b/sys/powerpc/powerpc/swtch64.S
--- a/sys/powerpc/powerpc/swtch64.S
+++ b/sys/powerpc/powerpc/swtch64.S
@@ -131,6 +131,8 @@
stdu %r1,-48(%r1)
+ /* Keep this next section in sync with cpu_save_thread_regs()! */
+
lwz %r18, PCB_FLAGS(%r17)
andi. %r7, %r18, PCB_CFSCR
beq 1f
diff --git a/sys/powerpc/powerpc/vm_machdep.c b/sys/powerpc/powerpc/vm_machdep.c
--- a/sys/powerpc/powerpc/vm_machdep.c
+++ b/sys/powerpc/powerpc/vm_machdep.c
@@ -91,6 +91,7 @@
#include <machine/frame.h>
#include <machine/md_var.h>
#include <machine/pcb.h>
+#include <machine/reg.h>
#include <dev/ofw/openfirm.h>
@@ -121,6 +122,10 @@
if ((flags & RFPROC) == 0)
return;
+ /* Ensure td1 is up to date before copy. */
+ if (td1 == curthread)
+ cpu_save_thread_regs(td1);
+
pcb = (struct pcb *)((td2->td_kstack +
td2->td_kstack_pages * PAGE_SIZE - sizeof(struct pcb)) & ~0x2fUL);
td2->td_pcb = pcb;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Apr 2, 7:17 AM (1 h, 30 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28242915
Default Alt Text
D29851.1775114240.diff (3 KB)
Attached To
Mode
D29851: [PowerPC] Fix outdated FP regs on fork(2) and friends
Attached
Detach File
Event Timeline
Log In to Comment