From: "Mallick, Asit K" <asit.k.mallick@intel.com>
To: linux-ia64@vger.kernel.org
Subject: RE: [Linux-ia64] High fpu register corruption (PATCH)
Date: Thu, 22 May 2003 21:55:36 +0000 [thread overview]
Message-ID: <marc-linux-ia64-105590723705988@msgid-missing> (raw)
In-Reply-To: <marc-linux-ia64-105590723705679@msgid-missing>
[-- Attachment #1: Type: text/plain, Size: 2527 bytes --]
Attached is a patch to fix the high FPU corruption (thanks to Andreas
and Chris). This patch also unifies the FPU save/restore for SMP and UP
and also fixes another problem with FPH save/restore path due to an
unaligned fault. Sorry for the delay.
This patch based on 2.4.21-rc2 (latest bktree).
Thanks,
Asit
> From: Mallick, Asit K
> Sent: Thursday, May 08, 2003 10:14 AM
> To: davidm@hpl.hp.com; Andreas Schwab
> Cc: linux-ia64@linuxia64.org; Chris Mason
> Subject: RE: [Linux-ia64] High fpu register corruption
>
> David,
>
> The save part in the context switch also needs to be fixed and we will
> take a look at this.
> Thanks,
> Asit
>
>
> > -----Original Message-----
> > From: David Mosberger [mailto:davidm@napali.hpl.hp.com]
> > Sent: Thursday, May 08, 2003 10:03 AM
> > To: Andreas Schwab
> > Cc: linux-ia64@linuxia64.org; Chris Mason
> > Subject: Re: [Linux-ia64] High fpu register corruption
> >
> > >>>>> On Thu, 08 May 2003 16:16:13 +0200, Andreas Schwab
> <schwab@suse.de>
> > said:
> >
> > Andreas> When a process clears the psr.mfh bit after using the
high
> > Andreas> fpu registers and then starts using them again it can
> > Andreas> corrupt the fpu state of another process. In order for
> > Andreas> this to happen there must be some context switches
> > Andreas> inbetween (thanks to Chris Mason for tracking this down):
> >
> > Ah, _now_ it makes sense. I got a similar bug report yesterday, but
> > it claimed the _old_ (2.4.19) context switch was breaking and the
> > new one (2.4.20) was fine. When I looked at the old code, I
couldn't
> > find anythign wrong with it.
> >
> > Andreas> + } else if (ia64_get_fpu_owner() != next)
> \
> > Andreas> + ia64_psr(ia64_task_regs(next))->dfh = 1;
> \
> >
> > I suspect what we really want to do here is something along the
lines
> > of:
> >
> > Andreas> + ia64_psr(ia64_task_regs(next))->dfh =
> > (ia64_get_fpu_owner() != next); \
> >
> > This expresses the invariant we're after: the next thread has DFH
set
> > unless it owns the FPH partition. IIRC, this is what the UP code
does
> > already.
> >
> > --david
> >
> > _______________________________________________
> > Linux-IA64 mailing list
> > Linux-IA64@linuxia64.org
> > http://lists.linuxia64.org/lists/listinfo/linux-ia64
>
> _______________________________________________
> Linux-IA64 mailing list
> Linux-IA64@linuxia64.org
> http://lists.linuxia64.org/lists/listinfo/linux-ia64
[-- Attachment #2: lazyfp1_7-24.txt --]
[-- Type: text/plain, Size: 9619 bytes --]
# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.1130 -> 1.1133
# arch/ia64/kernel/setup.c 1.12 -> 1.14
# include/asm-ia64/processor.h 1.19 -> 1.21
# include/asm-ia64/system.h 1.18 -> 1.19
# arch/ia64/kernel/process.c 1.18 -> 1.19
# arch/ia64/kernel/signal.c 1.14 -> 1.15
# arch/ia64/kernel/traps.c 1.13 -> 1.15
# arch/ia64/kernel/ptrace.c 1.17 -> 1.19
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/05/21 adsharma@linux-t08.(none) 1.1131
# lazyfp1.5-24
# --------------------------------------------
# 03/05/21 adsharma@linux-t08.(none) 1.1132
# fph corruption fix
# --------------------------------------------
# 03/05/22 adsharma@linux-t08.(none) 1.1133
# UP fixes
# --------------------------------------------
#
diff -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
--- a/arch/ia64/kernel/process.c Thu May 22 14:25:13 2003
+++ b/arch/ia64/kernel/process.c Thu May 22 14:25:13 2003
@@ -333,6 +333,7 @@
# define THREAD_FLAGS_TO_SET 0
p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR)
| THREAD_FLAGS_TO_SET);
+ ia64_drop_fpu(p); /* don't pick up stale state from a CPU's fph */
#ifdef CONFIG_IA32_SUPPORT
/*
* If we're cloning an IA32 task then save the IA32 extra
@@ -517,11 +518,7 @@
{
/* drop floating-point and debug-register state if it exists: */
current->thread.flags &= ~(IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID);
-
-#ifndef CONFIG_SMP
- if (ia64_get_fpu_owner() == current)
- ia64_set_fpu_owner(0);
-#endif
+ ia64_drop_fpu(current);
}
#ifdef CONFIG_PERFMON
@@ -559,10 +556,7 @@
void
exit_thread (void)
{
-#ifndef CONFIG_SMP
- if (ia64_get_fpu_owner() == current)
- ia64_set_fpu_owner(0);
-#endif
+ ia64_drop_fpu(current);
#ifdef CONFIG_PERFMON
/* stop monitoring */
if (current->thread.pfm_context)
diff -Nru a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
--- a/arch/ia64/kernel/ptrace.c Thu May 22 14:25:13 2003
+++ b/arch/ia64/kernel/ptrace.c Thu May 22 14:25:13 2003
@@ -597,16 +597,11 @@
ia64_flush_fph (struct task_struct *task)
{
struct ia64_psr *psr = ia64_psr(ia64_task_regs(task));
-#ifdef CONFIG_SMP
- struct task_struct *fpu_owner = current;
-#else
- struct task_struct *fpu_owner = ia64_get_fpu_owner();
-#endif
- if (task == fpu_owner && psr->mfh) {
+ if (ia64_is_local_fpu_owner(task) && psr->mfh) {
psr->mfh = 0;
- ia64_save_fpu(&task->thread.fph[0]);
task->thread.flags |= IA64_THREAD_FPH_VALID;
+ ia64_save_fpu(&task->thread.fph[0]);
}
}
@@ -628,10 +623,7 @@
task->thread.flags |= IA64_THREAD_FPH_VALID;
memset(&task->thread.fph, 0, sizeof(task->thread.fph));
}
-#ifndef CONFIG_SMP
- if (ia64_get_fpu_owner() == task)
- ia64_set_fpu_owner(0);
-#endif
+ ia64_drop_fpu(task);
psr->dfh = 1;
}
diff -Nru a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
--- a/arch/ia64/kernel/setup.c Thu May 22 14:25:13 2003
+++ b/arch/ia64/kernel/setup.c Thu May 22 14:25:13 2003
@@ -619,6 +619,8 @@
/* Clear the stack memory reserved for pt_regs: */
memset(ia64_task_regs(current), 0, sizeof(struct pt_regs));
+ ia64_set_kr(IA64_KR_FPU_OWNER, 0);
+
/*
* Initialize default control register to defer all speculative faults. The
* kernel MUST NOT depend on a particular setting of these bits (in other words,
@@ -629,10 +631,6 @@
*/
ia64_set_dcr( IA64_DCR_DP | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_DR
| IA64_DCR_DA | IA64_DCR_DD | IA64_DCR_LC);
-#ifndef CONFIG_SMP
- ia64_set_fpu_owner(0);
-#endif
-
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
diff -Nru a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
--- a/arch/ia64/kernel/signal.c Thu May 22 14:25:13 2003
+++ b/arch/ia64/kernel/signal.c Thu May 22 14:25:13 2003
@@ -142,8 +142,12 @@
__copy_from_user(current->thread.fph, &sc->sc_fr[32], 96*16);
psr->mfh = 0; /* drop signal handler's fph contents... */
- if (!psr->dfh)
+ if (!psr->dfh) {
__ia64_load_fpu(current->thread.fph);
+ ia64_set_local_fpu_owner(current);
+ } else {
+ ia64_drop_fpu(current);
+ }
}
return err;
}
diff -Nru a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
--- a/arch/ia64/kernel/traps.c Thu May 22 14:25:13 2003
+++ b/arch/ia64/kernel/traps.c Thu May 22 14:25:13 2003
@@ -245,9 +245,9 @@
psr->dfh = 0;
#ifndef CONFIG_SMP
{
- struct task_struct *fpu_owner = ia64_get_fpu_owner();
+ struct task_struct *fpu_owner = (struct task_struct *)ia64_get_kr(IA64_KR_FPU_OWNER);
- if (fpu_owner == current)
+ if (ia64_is_local_fpu_owner(current))
return;
if (fpu_owner)
@@ -255,7 +255,7 @@
}
#endif /* !CONFIG_SMP */
- ia64_set_fpu_owner(current);
+ ia64_set_local_fpu_owner(current);
if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) {
__ia64_load_fpu(current->thread.fph);
psr->mfh = 0;
diff -Nru a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
--- a/include/asm-ia64/processor.h Thu May 22 14:25:13 2003
+++ b/include/asm-ia64/processor.h Thu May 22 14:25:13 2003
@@ -302,7 +302,8 @@
INIT_THREAD_PM \
{0, }, /* dbr */ \
{0, }, /* ibr */ \
- {{{{0}}}, } /* fph */ \
+ {{{{0}}}, }, /* fph */ \
+ -1 /* last_fph_cpu*/ \
}
#define start_thread(regs,new_ip,new_sp) do { \
@@ -426,17 +427,16 @@
}
}
-static inline struct task_struct *
-ia64_get_fpu_owner (void)
-{
- return (struct task_struct *) ia64_get_kr(IA64_KR_FPU_OWNER);
-}
+#define ia64_is_local_fpu_owner(t) (((t)->thread.last_fph_cpu == smp_processor_id()) && \
+ ((t) == (struct task_struct *)ia64_get_kr(IA64_KR_FPU_OWNER)))
-static inline void
-ia64_set_fpu_owner (struct task_struct *t)
-{
- ia64_set_kr(IA64_KR_FPU_OWNER, (unsigned long) t);
-}
+#define ia64_set_local_fpu_owner(t) do { \
+ t->thread.last_fph_cpu = smp_processor_id(); \
+ ia64_set_kr(IA64_KR_FPU_OWNER, (unsigned long) (t)); \
+} while(0)
+
+/* Mark the fph partition of task T as being invalid on all CPUs. */
+#define ia64_drop_fpu(t) ((t)->thread.last_fph_cpu = -1)
extern void __ia64_init_fpu (void);
extern void __ia64_save_fpu (struct ia64_fpreg *fph);
diff -Nru a/include/asm-ia64/system.h b/include/asm-ia64/system.h
--- a/include/asm-ia64/system.h Thu May 22 14:25:13 2003
+++ b/include/asm-ia64/system.h Thu May 22 14:25:13 2003
@@ -244,13 +244,16 @@
# define PERFMON_IS_SYSWIDE() (0)
#endif
+#define IA64_HAS_EXTRA_STATE(t) \
+ ((t)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID) \
+ || IS_IA32_PROCESS(ia64_task_regs(t)) || PERFMON_IS_SYSWIDE())
+
#define __switch_to(prev,next,last) do { \
- if (((prev)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID)) \
- || IS_IA32_PROCESS(ia64_task_regs(prev)) || PERFMON_IS_SYSWIDE()) \
- ia64_save_extra(prev); \
- if (((next)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID)) \
- || IS_IA32_PROCESS(ia64_task_regs(next)) || PERFMON_IS_SYSWIDE()) \
+ if (IA64_HAS_EXTRA_STATE(prev)) \
+ ia64_save_extra(prev); \
+ if (IA64_HAS_EXTRA_STATE(next)) \
ia64_load_extra(next); \
+ ia64_psr(ia64_task_regs(next))->dfh = !ia64_is_local_fpu_owner(next); \
(last) = ia64_switch_to((next)); \
} while (0)
@@ -260,35 +263,21 @@
#define arch_consoles_callable() (cpu_online_map & (1UL << smp_processor_id()))
/*
- * In the SMP case, we save the fph state when context-switching
- * away from a thread that modified fph. This way, when the thread
- * gets scheduled on another CPU, the CPU can pick up the state from
- * task->thread.fph, avoiding the complication of having to fetch
- * the latest fph state from another CPU.
+ * In the SMP case, we save the fph state when context-switching away from a thread that
+ * modified fph. This way, when the thread gets scheduled on another CPU, the CPU can
+ * pick up the state from task->thread.fph, avoiding the complication of having to fetch
+ * the latest fph state from another CPU. In other words: eager save, lazy restore.
*/
# define switch_to(prev,next,last) do { \
- if (ia64_psr(ia64_task_regs(prev))->mfh) { \
+ if (ia64_psr(ia64_task_regs(prev))->mfh) { \
ia64_psr(ia64_task_regs(prev))->mfh = 0; \
(prev)->thread.flags |= IA64_THREAD_FPH_VALID; \
__ia64_save_fpu((prev)->thread.fph); \
- (prev)->thread.last_fph_cpu = smp_processor_id(); \
- } \
- if ((next)->thread.flags & IA64_THREAD_FPH_VALID) { \
- if (((next)->thread.last_fph_cpu == smp_processor_id()) \
- && (ia64_get_fpu_owner() == next)) { \
- ia64_psr(ia64_task_regs(next))->dfh = 0; \
- ia64_psr(ia64_task_regs(next))->mfh = 0; \
- } else { \
- ia64_psr(ia64_task_regs(next))->dfh = 1; \
- } \
} \
- __switch_to(prev,next,last); \
+ __switch_to(prev, next, last); \
} while (0)
#else
-# define switch_to(prev,next,last) do { \
- ia64_psr(ia64_task_regs(next))->dfh = (ia64_get_fpu_owner() != (next)); \
- __switch_to(prev,next,last); \
-} while (0)
+# define switch_to(prev,next,last) __switch_to(prev,next,last)
#endif
#endif /* __KERNEL__ */
next prev parent reply other threads:[~2003-05-22 21:55 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-05-08 14:16 [Linux-ia64] High fpu register corruption Andreas Schwab
2003-05-08 16:33 ` Mallick, Asit K
2003-05-08 16:42 ` Chris Mason
2003-05-08 16:58 ` David Mosberger
2003-05-08 17:03 ` David Mosberger
2003-05-08 17:14 ` Mallick, Asit K
2003-05-08 17:55 ` David Mosberger
2003-05-22 21:55 ` Mallick, Asit K [this message]
2003-05-29 3:53 ` [Linux-ia64] High fpu register corruption (PATCH) Bjorn Helgaas
2003-05-29 4:10 ` David Mosberger
2003-05-29 4:25 ` Bjorn Helgaas
2003-05-29 4:40 ` David Mosberger
2003-05-29 5:43 ` Mallick, Asit K
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=marc-linux-ia64-105590723705988@msgid-missing \
--to=asit.k.mallick@intel.com \
--cc=linux-ia64@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox