* [PATCH] MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS
@ 2015-01-08 12:17 ` Paul Burton
0 siblings, 0 replies; 18+ messages in thread
From: Paul Burton @ 2015-01-08 12:17 UTC (permalink / raw)
To: linux-mips; +Cc: Paul Burton, Matthew Fortune, Markos Chandras
Userland code may be built using an ABI which permits linking to objects
that have more restrictive floating point requirements. For example,
userland code may be built to target the O32 FPXX ABI. Such code may be
linked with other FPXX code, or code built for either one of the more
restrictive FP32 or FP64. When linking with more restrictive code, the
overall requirement of the process becomes that of the more restrictive
code. The kernel has no way to know in advance which mode the process
will need to be executed in, and indeed it may need to change during
execution. The dynamic loader is the only code which will know the
overall required mode, and so it needs to have a means to instruct the
kernel to switch the FP mode of the process.
This patch introduces 2 new options to the prctl syscall which provide
such a capability. The FP mode of the process is represented as a
simple bitmask combining a number of mode bits mirroring those present
in the hardware. Userland can either retrieve the current FP mode of
the process:
mode = prctl(PR_GET_FP_MODE);
or modify the current FP mode of the process:
err = prctl(PR_SET_FP_MODE, new_mode);
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Cc: Matthew Fortune <matthew.fortune@imgtec.com>
Cc: Markos Chandras <markos.chandras@imgtec.com>
---
arch/mips/include/asm/mmu.h | 3 ++
arch/mips/include/asm/mmu_context.h | 2 +
arch/mips/include/asm/processor.h | 11 +++++
arch/mips/kernel/process.c | 92 +++++++++++++++++++++++++++++++++++++
arch/mips/kernel/traps.c | 19 ++++++++
include/uapi/linux/prctl.h | 5 ++
kernel/sys.c | 12 +++++
7 files changed, 144 insertions(+)
diff --git a/arch/mips/include/asm/mmu.h b/arch/mips/include/asm/mmu.h
index c436138..1afa1f9 100644
--- a/arch/mips/include/asm/mmu.h
+++ b/arch/mips/include/asm/mmu.h
@@ -1,9 +1,12 @@
#ifndef __ASM_MMU_H
#define __ASM_MMU_H
+#include <linux/atomic.h>
+
typedef struct {
unsigned long asid[NR_CPUS];
void *vdso;
+ atomic_t fp_mode_switching;
} mm_context_t;
#endif /* __ASM_MMU_H */
diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h
index 2f82568..87f1107 100644
--- a/arch/mips/include/asm/mmu_context.h
+++ b/arch/mips/include/asm/mmu_context.h
@@ -132,6 +132,8 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm)
for_each_possible_cpu(i)
cpu_context(i, mm) = 0;
+ atomic_set(&mm->context.fp_mode_switching, 0);
+
return 0;
}
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
index f1df4cb..9daa386 100644
--- a/arch/mips/include/asm/processor.h
+++ b/arch/mips/include/asm/processor.h
@@ -399,4 +399,15 @@ unsigned long get_wchan(struct task_struct *p);
#endif
+/*
+ * Functions & macros implementing the PR_GET_FP_MODE & PR_SET_FP_MODE options
+ * to the prctl syscall.
+ */
+extern int mips_get_process_fp_mode(struct task_struct *task);
+extern int mips_set_process_fp_mode(struct task_struct *task,
+ unsigned int value);
+
+#define GET_FP_MODE(task) mips_get_process_fp_mode(task)
+#define SET_FP_MODE(task,value) mips_set_process_fp_mode(task, value)
+
#endif /* _ASM_PROCESSOR_H */
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index eb76434..b732c0c 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -25,6 +25,7 @@
#include <linux/completion.h>
#include <linux/kallsyms.h>
#include <linux/random.h>
+#include <linux/prctl.h>
#include <asm/asm.h>
#include <asm/bootinfo.h>
@@ -550,3 +551,94 @@ void arch_trigger_all_cpu_backtrace(bool include_self)
{
smp_call_function(arch_dump_stack, NULL, 1);
}
+
+int mips_get_process_fp_mode(struct task_struct *task)
+{
+ int value = 0;
+
+ if (!test_tsk_thread_flag(task, TIF_32BIT_FPREGS))
+ value |= PR_FP_MODE_FR;
+ if (test_tsk_thread_flag(task, TIF_HYBRID_FPREGS))
+ value |= PR_FP_MODE_FRE;
+
+ return value;
+}
+
+int mips_set_process_fp_mode(struct task_struct *task, unsigned int value)
+{
+ const unsigned int known_bits = PR_FP_MODE_FR | PR_FP_MODE_FRE;
+ unsigned long switch_count;
+ struct task_struct *t;
+
+ /* Check the value is valid */
+ if (value & ~known_bits)
+ return -EOPNOTSUPP;
+
+ /* Avoid inadvertently triggering emulation */
+ if ((value & PR_FP_MODE_FR) && cpu_has_fpu &&
+ !(current_cpu_data.fpu_id & MIPS_FPIR_F64))
+ return -EOPNOTSUPP;
+ if ((value & PR_FP_MODE_FRE) && !cpu_has_fre)
+ return -EOPNOTSUPP;
+
+ /* Save FP & vector context, then disable FPU & MSA */
+ if (task->signal == current->signal)
+ lose_fpu(1);
+
+ /* Prevent any threads from obtaining live FP context */
+ atomic_set(&task->mm->context.fp_mode_switching, 1);
+ smp_mb__after_atomic();
+
+ /*
+ * If there are multiple online CPUs then wait until all threads whose
+ * FP mode is about to change have been context switched. This approach
+ * allows us to only worry about whether an FP mode switch is in
+ * progress when FP is first used in a tasks time slice. Pretty much all
+ * of the mode switch overhead can thus be confined to cases where mode
+ * switches are actually occuring. That is, to here. However for the
+ * thread performing the mode switch it may take a while...
+ */
+ if (num_online_cpus() > 1) {
+ spin_lock_irq(&task->sighand->siglock);
+
+ for_each_thread(task, t) {
+ if (t == current)
+ continue;
+
+ switch_count = t->nvcsw + t->nivcsw;
+
+ do {
+ spin_unlock_irq(&task->sighand->siglock);
+ cond_resched();
+ spin_lock_irq(&task->sighand->siglock);
+ } while ((t->nvcsw + t->nivcsw) == switch_count);
+ }
+
+ spin_unlock_irq(&task->sighand->siglock);
+ }
+
+ /*
+ * There are now no threads of the process with live FP context, so it
+ * is safe to proceed with the FP mode switch.
+ */
+ for_each_thread(task, t) {
+ /* Update desired FP register width */
+ if (value & PR_FP_MODE_FR) {
+ clear_tsk_thread_flag(t, TIF_32BIT_FPREGS);
+ } else {
+ set_tsk_thread_flag(t, TIF_32BIT_FPREGS);
+ clear_tsk_thread_flag(t, TIF_MSA_CTX_LIVE);
+ }
+
+ /* Update desired FP single layout */
+ if (value & PR_FP_MODE_FRE)
+ set_tsk_thread_flag(t, TIF_HYBRID_FPREGS);
+ else
+ clear_tsk_thread_flag(t, TIF_HYBRID_FPREGS);
+ }
+
+ /* Allow threads to use FP again */
+ atomic_set(&task->mm->context.fp_mode_switching, 0);
+
+ return 0;
+}
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index ad3d203..d5fbfb5 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -1134,10 +1134,29 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
return NOTIFY_OK;
}
+static int wait_on_fp_mode_switch(atomic_t *p)
+{
+ /*
+ * The FP mode for this task is currently being switched. That may
+ * involve modifications to the format of this tasks FP context which
+ * make it unsafe to proceed with execution for the moment. Instead,
+ * schedule some other task.
+ */
+ schedule();
+ return 0;
+}
+
static int enable_restore_fp_context(int msa)
{
int err, was_fpu_owner, prior_msa;
+ /*
+ * If an FP mode switch is currently underway, wait for it to
+ * complete before proceeding.
+ */
+ wait_on_atomic_t(¤t->mm->context.fp_mode_switching,
+ wait_on_fp_mode_switch, TASK_KILLABLE);
+
if (!used_math()) {
/* First time FP context user. */
preempt_disable();
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index 89f6350..31891d9 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -185,4 +185,9 @@ struct prctl_mm_map {
#define PR_MPX_ENABLE_MANAGEMENT 43
#define PR_MPX_DISABLE_MANAGEMENT 44
+#define PR_SET_FP_MODE 45
+#define PR_GET_FP_MODE 46
+# define PR_FP_MODE_FR (1 << 0) /* 64b FP registers */
+# define PR_FP_MODE_FRE (1 << 1) /* 32b compatibility */
+
#endif /* _LINUX_PRCTL_H */
diff --git a/kernel/sys.c b/kernel/sys.c
index a8c9f5a..08b16bb 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -97,6 +97,12 @@
#ifndef MPX_DISABLE_MANAGEMENT
# define MPX_DISABLE_MANAGEMENT(a) (-EINVAL)
#endif
+#ifndef GET_FP_MODE
+# define GET_FP_MODE(a) (-EINVAL)
+#endif
+#ifndef SET_FP_MODE
+# define SET_FP_MODE(a,b) (-EINVAL)
+#endif
/*
* this is where the system-wide overflow UID and GID are defined, for
@@ -2215,6 +2221,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
case PR_MPX_DISABLE_MANAGEMENT:
error = MPX_DISABLE_MANAGEMENT(me);
break;
+ case PR_SET_FP_MODE:
+ error = SET_FP_MODE(me, arg2);
+ break;
+ case PR_GET_FP_MODE:
+ error = GET_FP_MODE(me);
+ break;
default:
error = -EINVAL;
break;
--
2.2.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH] MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS
@ 2015-01-08 12:17 ` Paul Burton
0 siblings, 0 replies; 18+ messages in thread
From: Paul Burton @ 2015-01-08 12:17 UTC (permalink / raw)
To: linux-mips; +Cc: Paul Burton, Matthew Fortune, Markos Chandras
Userland code may be built using an ABI which permits linking to objects
that have more restrictive floating point requirements. For example,
userland code may be built to target the O32 FPXX ABI. Such code may be
linked with other FPXX code, or code built for either one of the more
restrictive FP32 or FP64. When linking with more restrictive code, the
overall requirement of the process becomes that of the more restrictive
code. The kernel has no way to know in advance which mode the process
will need to be executed in, and indeed it may need to change during
execution. The dynamic loader is the only code which will know the
overall required mode, and so it needs to have a means to instruct the
kernel to switch the FP mode of the process.
This patch introduces 2 new options to the prctl syscall which provide
such a capability. The FP mode of the process is represented as a
simple bitmask combining a number of mode bits mirroring those present
in the hardware. Userland can either retrieve the current FP mode of
the process:
mode = prctl(PR_GET_FP_MODE);
or modify the current FP mode of the process:
err = prctl(PR_SET_FP_MODE, new_mode);
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Cc: Matthew Fortune <matthew.fortune@imgtec.com>
Cc: Markos Chandras <markos.chandras@imgtec.com>
---
arch/mips/include/asm/mmu.h | 3 ++
arch/mips/include/asm/mmu_context.h | 2 +
arch/mips/include/asm/processor.h | 11 +++++
arch/mips/kernel/process.c | 92 +++++++++++++++++++++++++++++++++++++
arch/mips/kernel/traps.c | 19 ++++++++
include/uapi/linux/prctl.h | 5 ++
kernel/sys.c | 12 +++++
7 files changed, 144 insertions(+)
diff --git a/arch/mips/include/asm/mmu.h b/arch/mips/include/asm/mmu.h
index c436138..1afa1f9 100644
--- a/arch/mips/include/asm/mmu.h
+++ b/arch/mips/include/asm/mmu.h
@@ -1,9 +1,12 @@
#ifndef __ASM_MMU_H
#define __ASM_MMU_H
+#include <linux/atomic.h>
+
typedef struct {
unsigned long asid[NR_CPUS];
void *vdso;
+ atomic_t fp_mode_switching;
} mm_context_t;
#endif /* __ASM_MMU_H */
diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h
index 2f82568..87f1107 100644
--- a/arch/mips/include/asm/mmu_context.h
+++ b/arch/mips/include/asm/mmu_context.h
@@ -132,6 +132,8 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm)
for_each_possible_cpu(i)
cpu_context(i, mm) = 0;
+ atomic_set(&mm->context.fp_mode_switching, 0);
+
return 0;
}
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
index f1df4cb..9daa386 100644
--- a/arch/mips/include/asm/processor.h
+++ b/arch/mips/include/asm/processor.h
@@ -399,4 +399,15 @@ unsigned long get_wchan(struct task_struct *p);
#endif
+/*
+ * Functions & macros implementing the PR_GET_FP_MODE & PR_SET_FP_MODE options
+ * to the prctl syscall.
+ */
+extern int mips_get_process_fp_mode(struct task_struct *task);
+extern int mips_set_process_fp_mode(struct task_struct *task,
+ unsigned int value);
+
+#define GET_FP_MODE(task) mips_get_process_fp_mode(task)
+#define SET_FP_MODE(task,value) mips_set_process_fp_mode(task, value)
+
#endif /* _ASM_PROCESSOR_H */
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index eb76434..b732c0c 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -25,6 +25,7 @@
#include <linux/completion.h>
#include <linux/kallsyms.h>
#include <linux/random.h>
+#include <linux/prctl.h>
#include <asm/asm.h>
#include <asm/bootinfo.h>
@@ -550,3 +551,94 @@ void arch_trigger_all_cpu_backtrace(bool include_self)
{
smp_call_function(arch_dump_stack, NULL, 1);
}
+
+int mips_get_process_fp_mode(struct task_struct *task)
+{
+ int value = 0;
+
+ if (!test_tsk_thread_flag(task, TIF_32BIT_FPREGS))
+ value |= PR_FP_MODE_FR;
+ if (test_tsk_thread_flag(task, TIF_HYBRID_FPREGS))
+ value |= PR_FP_MODE_FRE;
+
+ return value;
+}
+
+int mips_set_process_fp_mode(struct task_struct *task, unsigned int value)
+{
+ const unsigned int known_bits = PR_FP_MODE_FR | PR_FP_MODE_FRE;
+ unsigned long switch_count;
+ struct task_struct *t;
+
+ /* Check the value is valid */
+ if (value & ~known_bits)
+ return -EOPNOTSUPP;
+
+ /* Avoid inadvertently triggering emulation */
+ if ((value & PR_FP_MODE_FR) && cpu_has_fpu &&
+ !(current_cpu_data.fpu_id & MIPS_FPIR_F64))
+ return -EOPNOTSUPP;
+ if ((value & PR_FP_MODE_FRE) && !cpu_has_fre)
+ return -EOPNOTSUPP;
+
+ /* Save FP & vector context, then disable FPU & MSA */
+ if (task->signal == current->signal)
+ lose_fpu(1);
+
+ /* Prevent any threads from obtaining live FP context */
+ atomic_set(&task->mm->context.fp_mode_switching, 1);
+ smp_mb__after_atomic();
+
+ /*
+ * If there are multiple online CPUs then wait until all threads whose
+ * FP mode is about to change have been context switched. This approach
+ * allows us to only worry about whether an FP mode switch is in
+ * progress when FP is first used in a tasks time slice. Pretty much all
+ * of the mode switch overhead can thus be confined to cases where mode
+ * switches are actually occuring. That is, to here. However for the
+ * thread performing the mode switch it may take a while...
+ */
+ if (num_online_cpus() > 1) {
+ spin_lock_irq(&task->sighand->siglock);
+
+ for_each_thread(task, t) {
+ if (t == current)
+ continue;
+
+ switch_count = t->nvcsw + t->nivcsw;
+
+ do {
+ spin_unlock_irq(&task->sighand->siglock);
+ cond_resched();
+ spin_lock_irq(&task->sighand->siglock);
+ } while ((t->nvcsw + t->nivcsw) == switch_count);
+ }
+
+ spin_unlock_irq(&task->sighand->siglock);
+ }
+
+ /*
+ * There are now no threads of the process with live FP context, so it
+ * is safe to proceed with the FP mode switch.
+ */
+ for_each_thread(task, t) {
+ /* Update desired FP register width */
+ if (value & PR_FP_MODE_FR) {
+ clear_tsk_thread_flag(t, TIF_32BIT_FPREGS);
+ } else {
+ set_tsk_thread_flag(t, TIF_32BIT_FPREGS);
+ clear_tsk_thread_flag(t, TIF_MSA_CTX_LIVE);
+ }
+
+ /* Update desired FP single layout */
+ if (value & PR_FP_MODE_FRE)
+ set_tsk_thread_flag(t, TIF_HYBRID_FPREGS);
+ else
+ clear_tsk_thread_flag(t, TIF_HYBRID_FPREGS);
+ }
+
+ /* Allow threads to use FP again */
+ atomic_set(&task->mm->context.fp_mode_switching, 0);
+
+ return 0;
+}
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index ad3d203..d5fbfb5 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -1134,10 +1134,29 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
return NOTIFY_OK;
}
+static int wait_on_fp_mode_switch(atomic_t *p)
+{
+ /*
+ * The FP mode for this task is currently being switched. That may
+ * involve modifications to the format of this tasks FP context which
+ * make it unsafe to proceed with execution for the moment. Instead,
+ * schedule some other task.
+ */
+ schedule();
+ return 0;
+}
+
static int enable_restore_fp_context(int msa)
{
int err, was_fpu_owner, prior_msa;
+ /*
+ * If an FP mode switch is currently underway, wait for it to
+ * complete before proceeding.
+ */
+ wait_on_atomic_t(¤t->mm->context.fp_mode_switching,
+ wait_on_fp_mode_switch, TASK_KILLABLE);
+
if (!used_math()) {
/* First time FP context user. */
preempt_disable();
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index 89f6350..31891d9 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -185,4 +185,9 @@ struct prctl_mm_map {
#define PR_MPX_ENABLE_MANAGEMENT 43
#define PR_MPX_DISABLE_MANAGEMENT 44
+#define PR_SET_FP_MODE 45
+#define PR_GET_FP_MODE 46
+# define PR_FP_MODE_FR (1 << 0) /* 64b FP registers */
+# define PR_FP_MODE_FRE (1 << 1) /* 32b compatibility */
+
#endif /* _LINUX_PRCTL_H */
diff --git a/kernel/sys.c b/kernel/sys.c
index a8c9f5a..08b16bb 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -97,6 +97,12 @@
#ifndef MPX_DISABLE_MANAGEMENT
# define MPX_DISABLE_MANAGEMENT(a) (-EINVAL)
#endif
+#ifndef GET_FP_MODE
+# define GET_FP_MODE(a) (-EINVAL)
+#endif
+#ifndef SET_FP_MODE
+# define SET_FP_MODE(a,b) (-EINVAL)
+#endif
/*
* this is where the system-wide overflow UID and GID are defined, for
@@ -2215,6 +2221,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
case PR_MPX_DISABLE_MANAGEMENT:
error = MPX_DISABLE_MANAGEMENT(me);
break;
+ case PR_SET_FP_MODE:
+ error = SET_FP_MODE(me, arg2);
+ break;
+ case PR_GET_FP_MODE:
+ error = GET_FP_MODE(me);
+ break;
default:
error = -EINVAL;
break;
--
2.2.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* RE: [PATCH] MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS
2015-01-08 12:17 ` Paul Burton
(?)
@ 2015-01-08 12:54 ` Matthew Fortune
-1 siblings, 0 replies; 18+ messages in thread
From: Matthew Fortune @ 2015-01-08 12:54 UTC (permalink / raw)
To: Paul Burton, linux-mips@linux-mips.org; +Cc: Markos Chandras
> + /* Avoid inadvertently triggering emulation */
> + if ((value & PR_FP_MODE_FR) && cpu_has_fpu &&
> + !(current_cpu_data.fpu_id & MIPS_FPIR_F64))
> + return -EOPNOTSUPP;
> + if ((value & PR_FP_MODE_FRE) && !cpu_has_fre)
> + return -EOPNOTSUPP;
This is perhaps not important immediately but these two cases can
be seen as inconsistent. I.e. FR1 is emulated if there is no FPU
but FRE is not emulated if there is no FPU.
I believe this would be more consistent:
if ((value & PR_FP_MODE_FRE) && cpu_has_fpu &&
!cpu_has_fre)
return -EOPNOTSUPP;
The kernel then freely emulates any requested mode when there is
no FPU but sticks to only true hardware modes when there is an FPU.
= More detailed discussion =
There has been debate internally at IMG over the issue of FPU emulation
so I think it is appropriate to comment on why emulation is not always
desirable according to the new o32 FP ABI extensions. I'll try to be
brief...
The simple reason is that it is obviously better to use a true hardware
FPU mode whenever possible. Most of the o32 hard-float ABI variants
can execute in multiple hardware modes and the glibc dynamic linker
will probe to find the best supported hardware mode by trying them:
https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/mips/dl-machine-reject-phdr.h;h=b277450c4d02088acb8f24c74cea6ce04783688f;hb=0bd956720c457ff054325b48f26ac7c91cb060e8#l286
If an FPU exists but an emulated mode is used rather than a
true hardware mode then the code will run slower than necessary.
The second aspect to avoiding emulated modes is that users may
have multiple versions of an object available each with different
ABI extensions. If one fails to load then the next one may succeed
with a true hardware-supported mode.
With all that in mind I suspect we can find a balance (in a later
update) that may be able to balance the desire for emulation against
the desire for using real hardware modes. As it stands there is no
clear-cut answer or spec for this so I am in agreement with the
overall behaviour of this patch, perhaps with the tweak applied.
thanks,
Matthew
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS
@ 2015-01-09 2:25 ` Leonid Yegoshin
0 siblings, 0 replies; 18+ messages in thread
From: Leonid Yegoshin @ 2015-01-09 2:25 UTC (permalink / raw)
To: Paul Burton, linux-mips; +Cc: Matthew Fortune, Markos Chandras
> + /* Prevent any threads from obtaining live FP context */
> + atomic_set(&task->mm->context.fp_mode_switching, 1);
> + smp_mb__after_atomic();
> +
> + /*
> + * If there are multiple online CPUs then wait until all threads whose
> + * FP mode is about to change have been context switched. This approach
> + * allows us to only worry about whether an FP mode switch is in
> + * progress when FP is first used in a tasks time slice. Pretty much all
> + * of the mode switch overhead can thus be confined to cases where mode
> + * switches are actually occuring. That is, to here. However for the
> + * thread performing the mode switch it may take a while...
> + */
> + if (num_online_cpus() > 1) {
> + spin_lock_irq(&task->sighand->siglock);
> +
> + for_each_thread(task, t) {
> + if (t == current)
> + continue;
> +
> + switch_count = t->nvcsw + t->nivcsw;
> +
> + do {
> + spin_unlock_irq(&task->sighand->siglock);
> + cond_resched();
> + spin_lock_irq(&task->sighand->siglock);
> + } while ((t->nvcsw + t->nivcsw) == switch_count);
> + }
> +
> + spin_unlock_irq(&task->sighand->siglock);
> + }
>
This piece of thread walking seems to be not thread safe for newly
created thread.
Thread creation is not locked between points of copy_thread which copies
task thread flags
and makeing thread visible to walking via "for_each_thread".
So it is possible in environment with two threads - one is creating an
another thread,
another one switching FPU mode and waiting and race condition may causes
a newly thread in old mode
but the rest of thread group is in new mode.
Besides that, it looks like in kernel with tickless mode a scheduler may
no come a long time in idle system,
in extreme case - forever.
- Leonid.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS
@ 2015-01-09 2:25 ` Leonid Yegoshin
0 siblings, 0 replies; 18+ messages in thread
From: Leonid Yegoshin @ 2015-01-09 2:25 UTC (permalink / raw)
To: Paul Burton, linux-mips; +Cc: Matthew Fortune, Markos Chandras
> + /* Prevent any threads from obtaining live FP context */
> + atomic_set(&task->mm->context.fp_mode_switching, 1);
> + smp_mb__after_atomic();
> +
> + /*
> + * If there are multiple online CPUs then wait until all threads whose
> + * FP mode is about to change have been context switched. This approach
> + * allows us to only worry about whether an FP mode switch is in
> + * progress when FP is first used in a tasks time slice. Pretty much all
> + * of the mode switch overhead can thus be confined to cases where mode
> + * switches are actually occuring. That is, to here. However for the
> + * thread performing the mode switch it may take a while...
> + */
> + if (num_online_cpus() > 1) {
> + spin_lock_irq(&task->sighand->siglock);
> +
> + for_each_thread(task, t) {
> + if (t == current)
> + continue;
> +
> + switch_count = t->nvcsw + t->nivcsw;
> +
> + do {
> + spin_unlock_irq(&task->sighand->siglock);
> + cond_resched();
> + spin_lock_irq(&task->sighand->siglock);
> + } while ((t->nvcsw + t->nivcsw) == switch_count);
> + }
> +
> + spin_unlock_irq(&task->sighand->siglock);
> + }
>
This piece of thread walking seems to be not thread safe for newly
created thread.
Thread creation is not locked between points of copy_thread which copies
task thread flags
and makeing thread visible to walking via "for_each_thread".
So it is possible in environment with two threads - one is creating an
another thread,
another one switching FPU mode and waiting and race condition may causes
a newly thread in old mode
but the rest of thread group is in new mode.
Besides that, it looks like in kernel with tickless mode a scheduler may
no come a long time in idle system,
in extreme case - forever.
- Leonid.
^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS
2015-01-09 2:25 ` Leonid Yegoshin
(?)
@ 2015-01-09 8:34 ` Matthew Fortune
2015-01-09 18:42 ` Leonid Yegoshin
-1 siblings, 1 reply; 18+ messages in thread
From: Matthew Fortune @ 2015-01-09 8:34 UTC (permalink / raw)
To: Leonid Yegoshin, Paul Burton, linux-mips@linux-mips.org; +Cc: Markos Chandras
Leonid Yegoshin <Leonid.Yegoshin@imgtec.com> writes:
> > + /* Prevent any threads from obtaining live FP context */
> > + atomic_set(&task->mm->context.fp_mode_switching, 1);
> > + smp_mb__after_atomic();
> > +
> > + /*
> > + * If there are multiple online CPUs then wait until all threads
> whose
> > + * FP mode is about to change have been context switched. This
> approach
> > + * allows us to only worry about whether an FP mode switch is in
> > + * progress when FP is first used in a tasks time slice. Pretty
> much all
> > + * of the mode switch overhead can thus be confined to cases where
> mode
> > + * switches are actually occuring. That is, to here. However for
> the
> > + * thread performing the mode switch it may take a while...
> > + */
> > + if (num_online_cpus() > 1) {
> > + spin_lock_irq(&task->sighand->siglock);
> > +
> > + for_each_thread(task, t) {
> > + if (t == current)
> > + continue;
> > +
> > + switch_count = t->nvcsw + t->nivcsw;
> > +
> > + do {
> > + spin_unlock_irq(&task->sighand->siglock);
> > + cond_resched();
> > + spin_lock_irq(&task->sighand->siglock);
> > + } while ((t->nvcsw + t->nivcsw) == switch_count);
> > + }
> > +
> > + spin_unlock_irq(&task->sighand->siglock);
> > + }
> >
> This piece of thread walking seems to be not thread safe for newly
> created thread.
> Thread creation is not locked between points of copy_thread which copies
> task thread flags and makeing thread visible to walking via
> "for_each_thread".
>
> So it is possible in environment with two threads - one is creating an
> another thread, another one switching FPU mode and waiting and race
> condition may causes a newly thread in old mode but the rest of thread
> group is in new mode.
>
> Besides that, it looks like in kernel with tickless mode a scheduler may
> no come a long time in idle system, in extreme case - forever.
Only commenting on the tickless issue... The requirement for the
PR_SET_FP_MODE call is that all threads in the current thread group switch
to the new mode prior to it returning. I believe that simply means there
is no alternative other than for the tickless case to wait as long as it
has to wait? If the prctl failed in tickless mode (or timed out) then that
is likely to lead to a program failing to load its libraries and aborting.
So if the only other alternative is for the prctl to fail then I'm not
sure if that is any better than waiting forever.
For the vast majority of cases the prctl calls to change mode will happen
very early in the user-process, while it is still single threaded. These
will be part of loading an application's initial set of shared libraries.
Perhaps that means this corner case of a long delay is not overly dangerous
anyway?
Thanks,
Matthew
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS
2015-01-09 8:34 ` Matthew Fortune
@ 2015-01-09 18:42 ` Leonid Yegoshin
0 siblings, 0 replies; 18+ messages in thread
From: Leonid Yegoshin @ 2015-01-09 18:42 UTC (permalink / raw)
To: Matthew Fortune, Paul Burton, linux-mips@linux-mips.org; +Cc: Markos Chandras
On 01/09/2015 12:34 AM, Matthew Fortune wrote:
> Leonid Yegoshin <Leonid.Yegoshin@imgtec.com> writes:
>>
>> This piece of thread walking seems to be not thread safe for newly
>> created thread.
>> Thread creation is not locked between points of copy_thread which copies
>> task thread flags and makeing thread visible to walking via
>> "for_each_thread".
>>
>> So it is possible in environment with two threads - one is creating an
>> another thread, another one switching FPU mode and waiting and race
>> condition may causes a newly thread in old mode but the rest of thread
>> group is in new mode.
>>
>> Besides that, it looks like in kernel with tickless mode a scheduler may
>> no come a long time in idle system, in extreme case - forever.
> Only commenting on the tickless issue... The requirement for the
> PR_SET_FP_MODE call is that all threads in the current thread group switch
> to the new mode prior to it returning. I believe that simply means there
> is no alternative other than for the tickless case to wait as long as it
> has to wait? If the prctl failed in tickless mode (or timed out) then that
> is likely to lead to a program failing to load its libraries and aborting.
There is another design, which doesn't use walk through all thread group
and any scheduler wait.
It is based on IPI call to kick off threads-from-this-memory-map from
FPU usage in all CPUs and keeping/updating the real FPU mode flag in
memory map "context".
I have it and will post it to internal IMG mail list (currently, it
doesn't use "prctl" but "sysmips" syscall, and is designed around 3.10
kernel).
- Leonid.
^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS
@ 2015-01-09 21:25 ` Matthew Fortune
0 siblings, 0 replies; 18+ messages in thread
From: Matthew Fortune @ 2015-01-09 21:25 UTC (permalink / raw)
To: Leonid Yegoshin, Paul Burton, linux-mips@linux-mips.org; +Cc: Markos Chandras
Leonid Yegoshin <Leonid.Yegoshin@imgtec.com> writes:
> Matthew Fortune - 2015-01-08 12:01:50
>
> > > + /* Avoid inadvertently triggering emulation */
> > > + if ((value & PR_FP_MODE_FR) && cpu_has_fpu &&
> > > + !(current_cpu_data.fpu_id & MIPS_FPIR_F64))
> > > + return -EOPNOTSUPP;
> > > + if ((value & PR_FP_MODE_FRE) && !cpu_has_fre)
> > > + return -EOPNOTSUPP;
> >
> > This is perhaps not important immediately but these two cases can
> > be seen as inconsistent. I.e. FR1 is emulated if there is no FPU
> > but FRE is not emulated if there is no FPU.
> >
> > I believe this would be more consistent:
> >
> > if ((value & PR_FP_MODE_FRE) && cpu_has_fpu &&
> > !cpu_has_fre)
> > return -EOPNOTSUPP;
> >
> > The kernel then freely emulates any requested mode when there is
> > no FPU but sticks to only true hardware modes when there is an FPU.
> >
> > = More detailed discussion =
> >
> > There has been debate internally at IMG over the issue of FPU emulation
> > so I think it is appropriate to comment on why emulation is not always
> > desirable according to the new o32 FP ABI extensions. I'll try to be
> > brief...
> >
> > The simple reason is that it is obviously better to use a true hardware
> > FPU mode whenever possible.
>
> I would like to point you to fact that the best choice to use the hardware
> efficiently is to know which kind of hardware you have.
From that perspective the PR_SET_FP_MODE does just that except user-mode
discovers the modes by simply trying to use them in order of most desirable
to least desirable. I don't deny that the user code may benefit from knowing
upfront what is available and being able to select an emulated mode if it
*actively* chooses to do so.
> So, it would be much better if application (read - GLIBC/bionic library)
> gets the HW description available in HWCAP and make a choice during library load
> instead of guessing via syscalls in attempt to use one or another FPU/SIMD mode.
> Guessing may easily get a non-optimal HW configuration.
Guessing cannot get a non-optimal mode if the PR_SET_FP_MODE only succeeds for
true hardware modes. What can happen is that the user could fail to find a mode
that it needs even though the kernel could have emulated it. I agree that it may
be a useful to offer the user the opportunity to select an emulated mode though.
> And kernel can just support an application choice via using a real HW or emulation if
> application do some choice because there is no variants (example: FPU absence).
Would your concerns be addressed by adding another bit to the new PR_SET_FP_MODE
option that says the user is willing to accept an emulated mode:
#define PR_FP_MODE_EMU (1<<2)
I do not propose that this is returned from PR_GET_FP_MODE to indicate if
emulation is in use or not though. PR_GET_FP_MODE should just return the mode
in use regardless of emulation.
In addition to this extra control bit the updated behaviour of allowing a
PR_SET_FP_MODE without PR_FP_MODE_EMU should succeed if the current mode
matches the requested mode.
This gives the user the ability to choose a mode falling back to emulation if
they desire. Please bear in mind that this prctl call is for use solely in
dynamic linkers and other similar very low level system code. It is not a
general end user feature.
To find the best mode PR_SET_FP_MODE should then be used as follows with the
use of emulated modes carefully controlled to avoid unnecessary use.
1) dynamic linker needs FR0 mode:
Try PR_FP_MODE_FR0
Try PR_FP_MODE_FR1|PR_FP_MODE_FRE
Try PR_FP_MODE_EMU|PR_FP_MODE_FR0
Try PR_FP_MODE_EMU|PR_FP_MODE_FR1|PR_FP_MODE_FRE
2) dynamic linker needs FR1 mode:
Try PR_FP_MODE_FR1
Try PR_FP_MODE_EMU|PR_FP_MODE_FR1
3) dynamic linker needs FRE mode:
Try PR_FP_MODE_FRE
Try PR_FP_MODE_EMU|PR_FP_MODE_FRE
This is fully compatible with the dynamic linker implementation which is
already committed to glibc but allows the implementation to be extended
in further work to also enable the use of emulated modes. You can go as far
as to have a request to use an emulated mode actually disable an FPU even
if the hardware version of the mode is available!
I do not see any need for HWCAPs for these features as it is such a niche
area. These are fundamental ABI support details that should be hidden as
deeply as possible from an ordinary user.
Thanks,
Matthew
^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS
@ 2015-01-09 21:25 ` Matthew Fortune
0 siblings, 0 replies; 18+ messages in thread
From: Matthew Fortune @ 2015-01-09 21:25 UTC (permalink / raw)
To: Leonid Yegoshin, Paul Burton, linux-mips@linux-mips.org; +Cc: Markos Chandras
Leonid Yegoshin <Leonid.Yegoshin@imgtec.com> writes:
> Matthew Fortune - 2015-01-08 12:01:50
>
> > > + /* Avoid inadvertently triggering emulation */
> > > + if ((value & PR_FP_MODE_FR) && cpu_has_fpu &&
> > > + !(current_cpu_data.fpu_id & MIPS_FPIR_F64))
> > > + return -EOPNOTSUPP;
> > > + if ((value & PR_FP_MODE_FRE) && !cpu_has_fre)
> > > + return -EOPNOTSUPP;
> >
> > This is perhaps not important immediately but these two cases can
> > be seen as inconsistent. I.e. FR1 is emulated if there is no FPU
> > but FRE is not emulated if there is no FPU.
> >
> > I believe this would be more consistent:
> >
> > if ((value & PR_FP_MODE_FRE) && cpu_has_fpu &&
> > !cpu_has_fre)
> > return -EOPNOTSUPP;
> >
> > The kernel then freely emulates any requested mode when there is
> > no FPU but sticks to only true hardware modes when there is an FPU.
> >
> > = More detailed discussion =
> >
> > There has been debate internally at IMG over the issue of FPU emulation
> > so I think it is appropriate to comment on why emulation is not always
> > desirable according to the new o32 FP ABI extensions. I'll try to be
> > brief...
> >
> > The simple reason is that it is obviously better to use a true hardware
> > FPU mode whenever possible.
>
> I would like to point you to fact that the best choice to use the hardware
> efficiently is to know which kind of hardware you have.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH] MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS
2015-01-08 12:17 ` Paul Burton
(?)
@ 2015-01-13 13:12 ` Markos Chandras
-1 siblings, 0 replies; 18+ messages in thread
From: Markos Chandras @ 2015-01-13 13:12 UTC (permalink / raw)
To: Paul Burton, linux-mips-6z/3iImG2C8G8FEW9MqTrA
Cc: Matthew Fortune, LKML, linux-api-u79uwXL29TY76Z2rM5mHXA
On 01/08/2015 12:17 PM, Paul Burton wrote:
> Userland code may be built using an ABI which permits linking to objects
> that have more restrictive floating point requirements. For example,
> userland code may be built to target the O32 FPXX ABI. Such code may be
> linked with other FPXX code, or code built for either one of the more
> restrictive FP32 or FP64. When linking with more restrictive code, the
> overall requirement of the process becomes that of the more restrictive
> code. The kernel has no way to know in advance which mode the process
> will need to be executed in, and indeed it may need to change during
> execution. The dynamic loader is the only code which will know the
> overall required mode, and so it needs to have a means to instruct the
> kernel to switch the FP mode of the process.
>
> This patch introduces 2 new options to the prctl syscall which provide
> such a capability. The FP mode of the process is represented as a
> simple bitmask combining a number of mode bits mirroring those present
> in the hardware. Userland can either retrieve the current FP mode of
> the process:
>
> mode = prctl(PR_GET_FP_MODE);
>
> or modify the current FP mode of the process:
>
> err = prctl(PR_SET_FP_MODE, new_mode);
>
> Signed-off-by: Paul Burton <paul.burton-1AXoQHu6uovQT0dZR+AlfA@public.gmane.org>
> Cc: Matthew Fortune <matthew.fortune-1AXoQHu6uovQT0dZR+AlfA@public.gmane.org>
> Cc: Markos Chandras <markos.chandras-1AXoQHu6uovQT0dZR+AlfA@public.gmane.org>
Hi,
I think the "MIPS,prctl" in the title should be "MIPS: prctl"
I have also CC'd the LKML and the linux-api mailing lists since this
touches the kernel ABI with the new PR_[GS]ET_FP_MODE definitions.
(I intentionally leave the contents of the patch below so people can
comment on it)
> ---
> arch/mips/include/asm/mmu.h | 3 ++
> arch/mips/include/asm/mmu_context.h | 2 +
> arch/mips/include/asm/processor.h | 11 +++++
> arch/mips/kernel/process.c | 92 +++++++++++++++++++++++++++++++++++++
> arch/mips/kernel/traps.c | 19 ++++++++
> include/uapi/linux/prctl.h | 5 ++
> kernel/sys.c | 12 +++++
> 7 files changed, 144 insertions(+)
>
> diff --git a/arch/mips/include/asm/mmu.h b/arch/mips/include/asm/mmu.h
> index c436138..1afa1f9 100644
> --- a/arch/mips/include/asm/mmu.h
> +++ b/arch/mips/include/asm/mmu.h
> @@ -1,9 +1,12 @@
> #ifndef __ASM_MMU_H
> #define __ASM_MMU_H
>
> +#include <linux/atomic.h>
> +
> typedef struct {
> unsigned long asid[NR_CPUS];
> void *vdso;
> + atomic_t fp_mode_switching;
> } mm_context_t;
>
> #endif /* __ASM_MMU_H */
> diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h
> index 2f82568..87f1107 100644
> --- a/arch/mips/include/asm/mmu_context.h
> +++ b/arch/mips/include/asm/mmu_context.h
> @@ -132,6 +132,8 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm)
> for_each_possible_cpu(i)
> cpu_context(i, mm) = 0;
>
> + atomic_set(&mm->context.fp_mode_switching, 0);
> +
> return 0;
> }
>
> diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
> index f1df4cb..9daa386 100644
> --- a/arch/mips/include/asm/processor.h
> +++ b/arch/mips/include/asm/processor.h
> @@ -399,4 +399,15 @@ unsigned long get_wchan(struct task_struct *p);
>
> #endif
>
> +/*
> + * Functions & macros implementing the PR_GET_FP_MODE & PR_SET_FP_MODE options
> + * to the prctl syscall.
> + */
> +extern int mips_get_process_fp_mode(struct task_struct *task);
> +extern int mips_set_process_fp_mode(struct task_struct *task,
> + unsigned int value);
> +
> +#define GET_FP_MODE(task) mips_get_process_fp_mode(task)
> +#define SET_FP_MODE(task,value) mips_set_process_fp_mode(task, value)
> +
> #endif /* _ASM_PROCESSOR_H */
> diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
> index eb76434..b732c0c 100644
> --- a/arch/mips/kernel/process.c
> +++ b/arch/mips/kernel/process.c
> @@ -25,6 +25,7 @@
> #include <linux/completion.h>
> #include <linux/kallsyms.h>
> #include <linux/random.h>
> +#include <linux/prctl.h>
>
> #include <asm/asm.h>
> #include <asm/bootinfo.h>
> @@ -550,3 +551,94 @@ void arch_trigger_all_cpu_backtrace(bool include_self)
> {
> smp_call_function(arch_dump_stack, NULL, 1);
> }
> +
> +int mips_get_process_fp_mode(struct task_struct *task)
> +{
> + int value = 0;
> +
> + if (!test_tsk_thread_flag(task, TIF_32BIT_FPREGS))
> + value |= PR_FP_MODE_FR;
> + if (test_tsk_thread_flag(task, TIF_HYBRID_FPREGS))
> + value |= PR_FP_MODE_FRE;
> +
> + return value;
> +}
> +
> +int mips_set_process_fp_mode(struct task_struct *task, unsigned int value)
> +{
> + const unsigned int known_bits = PR_FP_MODE_FR | PR_FP_MODE_FRE;
> + unsigned long switch_count;
> + struct task_struct *t;
> +
> + /* Check the value is valid */
> + if (value & ~known_bits)
> + return -EOPNOTSUPP;
> +
> + /* Avoid inadvertently triggering emulation */
> + if ((value & PR_FP_MODE_FR) && cpu_has_fpu &&
> + !(current_cpu_data.fpu_id & MIPS_FPIR_F64))
> + return -EOPNOTSUPP;
> + if ((value & PR_FP_MODE_FRE) && !cpu_has_fre)
> + return -EOPNOTSUPP;
> +
> + /* Save FP & vector context, then disable FPU & MSA */
> + if (task->signal == current->signal)
> + lose_fpu(1);
> +
> + /* Prevent any threads from obtaining live FP context */
> + atomic_set(&task->mm->context.fp_mode_switching, 1);
> + smp_mb__after_atomic();
> +
> + /*
> + * If there are multiple online CPUs then wait until all threads whose
> + * FP mode is about to change have been context switched. This approach
> + * allows us to only worry about whether an FP mode switch is in
> + * progress when FP is first used in a tasks time slice. Pretty much all
> + * of the mode switch overhead can thus be confined to cases where mode
> + * switches are actually occuring. That is, to here. However for the
> + * thread performing the mode switch it may take a while...
> + */
> + if (num_online_cpus() > 1) {
> + spin_lock_irq(&task->sighand->siglock);
> +
> + for_each_thread(task, t) {
> + if (t == current)
> + continue;
> +
> + switch_count = t->nvcsw + t->nivcsw;
> +
> + do {
> + spin_unlock_irq(&task->sighand->siglock);
> + cond_resched();
> + spin_lock_irq(&task->sighand->siglock);
> + } while ((t->nvcsw + t->nivcsw) == switch_count);
> + }
> +
> + spin_unlock_irq(&task->sighand->siglock);
> + }
> +
> + /*
> + * There are now no threads of the process with live FP context, so it
> + * is safe to proceed with the FP mode switch.
> + */
> + for_each_thread(task, t) {
> + /* Update desired FP register width */
> + if (value & PR_FP_MODE_FR) {
> + clear_tsk_thread_flag(t, TIF_32BIT_FPREGS);
> + } else {
> + set_tsk_thread_flag(t, TIF_32BIT_FPREGS);
> + clear_tsk_thread_flag(t, TIF_MSA_CTX_LIVE);
> + }
> +
> + /* Update desired FP single layout */
> + if (value & PR_FP_MODE_FRE)
> + set_tsk_thread_flag(t, TIF_HYBRID_FPREGS);
> + else
> + clear_tsk_thread_flag(t, TIF_HYBRID_FPREGS);
> + }
> +
> + /* Allow threads to use FP again */
> + atomic_set(&task->mm->context.fp_mode_switching, 0);
> +
> + return 0;
> +}
> diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
> index ad3d203..d5fbfb5 100644
> --- a/arch/mips/kernel/traps.c
> +++ b/arch/mips/kernel/traps.c
> @@ -1134,10 +1134,29 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
> return NOTIFY_OK;
> }
>
> +static int wait_on_fp_mode_switch(atomic_t *p)
> +{
> + /*
> + * The FP mode for this task is currently being switched. That may
> + * involve modifications to the format of this tasks FP context which
> + * make it unsafe to proceed with execution for the moment. Instead,
> + * schedule some other task.
> + */
> + schedule();
> + return 0;
> +}
> +
> static int enable_restore_fp_context(int msa)
> {
> int err, was_fpu_owner, prior_msa;
>
> + /*
> + * If an FP mode switch is currently underway, wait for it to
> + * complete before proceeding.
> + */
> + wait_on_atomic_t(¤t->mm->context.fp_mode_switching,
> + wait_on_fp_mode_switch, TASK_KILLABLE);
> +
> if (!used_math()) {
> /* First time FP context user. */
> preempt_disable();
> diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
> index 89f6350..31891d9 100644
> --- a/include/uapi/linux/prctl.h
> +++ b/include/uapi/linux/prctl.h
> @@ -185,4 +185,9 @@ struct prctl_mm_map {
> #define PR_MPX_ENABLE_MANAGEMENT 43
> #define PR_MPX_DISABLE_MANAGEMENT 44
>
> +#define PR_SET_FP_MODE 45
> +#define PR_GET_FP_MODE 46
> +# define PR_FP_MODE_FR (1 << 0) /* 64b FP registers */
> +# define PR_FP_MODE_FRE (1 << 1) /* 32b compatibility */
> +
> #endif /* _LINUX_PRCTL_H */
> diff --git a/kernel/sys.c b/kernel/sys.c
> index a8c9f5a..08b16bb 100644
> --- a/kernel/sys.c
> +++ b/kernel/sys.c
> @@ -97,6 +97,12 @@
> #ifndef MPX_DISABLE_MANAGEMENT
> # define MPX_DISABLE_MANAGEMENT(a) (-EINVAL)
> #endif
> +#ifndef GET_FP_MODE
> +# define GET_FP_MODE(a) (-EINVAL)
> +#endif
> +#ifndef SET_FP_MODE
> +# define SET_FP_MODE(a,b) (-EINVAL)
> +#endif
>
> /*
> * this is where the system-wide overflow UID and GID are defined, for
> @@ -2215,6 +2221,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
> case PR_MPX_DISABLE_MANAGEMENT:
> error = MPX_DISABLE_MANAGEMENT(me);
> break;
> + case PR_SET_FP_MODE:
> + error = SET_FP_MODE(me, arg2);
> + break;
> + case PR_GET_FP_MODE:
> + error = GET_FP_MODE(me);
> + break;
> default:
> error = -EINVAL;
> break;
>
--
markos
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH] MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS
@ 2015-01-13 13:12 ` Markos Chandras
0 siblings, 0 replies; 18+ messages in thread
From: Markos Chandras @ 2015-01-13 13:12 UTC (permalink / raw)
To: Paul Burton, linux-mips; +Cc: Matthew Fortune, LKML, linux-api
On 01/08/2015 12:17 PM, Paul Burton wrote:
> Userland code may be built using an ABI which permits linking to objects
> that have more restrictive floating point requirements. For example,
> userland code may be built to target the O32 FPXX ABI. Such code may be
> linked with other FPXX code, or code built for either one of the more
> restrictive FP32 or FP64. When linking with more restrictive code, the
> overall requirement of the process becomes that of the more restrictive
> code. The kernel has no way to know in advance which mode the process
> will need to be executed in, and indeed it may need to change during
> execution. The dynamic loader is the only code which will know the
> overall required mode, and so it needs to have a means to instruct the
> kernel to switch the FP mode of the process.
>
> This patch introduces 2 new options to the prctl syscall which provide
> such a capability. The FP mode of the process is represented as a
> simple bitmask combining a number of mode bits mirroring those present
> in the hardware. Userland can either retrieve the current FP mode of
> the process:
>
> mode = prctl(PR_GET_FP_MODE);
>
> or modify the current FP mode of the process:
>
> err = prctl(PR_SET_FP_MODE, new_mode);
>
> Signed-off-by: Paul Burton <paul.burton@imgtec.com>
> Cc: Matthew Fortune <matthew.fortune@imgtec.com>
> Cc: Markos Chandras <markos.chandras@imgtec.com>
Hi,
I think the "MIPS,prctl" in the title should be "MIPS: prctl"
I have also CC'd the LKML and the linux-api mailing lists since this
touches the kernel ABI with the new PR_[GS]ET_FP_MODE definitions.
(I intentionally leave the contents of the patch below so people can
comment on it)
> ---
> arch/mips/include/asm/mmu.h | 3 ++
> arch/mips/include/asm/mmu_context.h | 2 +
> arch/mips/include/asm/processor.h | 11 +++++
> arch/mips/kernel/process.c | 92 +++++++++++++++++++++++++++++++++++++
> arch/mips/kernel/traps.c | 19 ++++++++
> include/uapi/linux/prctl.h | 5 ++
> kernel/sys.c | 12 +++++
> 7 files changed, 144 insertions(+)
>
> diff --git a/arch/mips/include/asm/mmu.h b/arch/mips/include/asm/mmu.h
> index c436138..1afa1f9 100644
> --- a/arch/mips/include/asm/mmu.h
> +++ b/arch/mips/include/asm/mmu.h
> @@ -1,9 +1,12 @@
> #ifndef __ASM_MMU_H
> #define __ASM_MMU_H
>
> +#include <linux/atomic.h>
> +
> typedef struct {
> unsigned long asid[NR_CPUS];
> void *vdso;
> + atomic_t fp_mode_switching;
> } mm_context_t;
>
> #endif /* __ASM_MMU_H */
> diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h
> index 2f82568..87f1107 100644
> --- a/arch/mips/include/asm/mmu_context.h
> +++ b/arch/mips/include/asm/mmu_context.h
> @@ -132,6 +132,8 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm)
> for_each_possible_cpu(i)
> cpu_context(i, mm) = 0;
>
> + atomic_set(&mm->context.fp_mode_switching, 0);
> +
> return 0;
> }
>
> diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
> index f1df4cb..9daa386 100644
> --- a/arch/mips/include/asm/processor.h
> +++ b/arch/mips/include/asm/processor.h
> @@ -399,4 +399,15 @@ unsigned long get_wchan(struct task_struct *p);
>
> #endif
>
> +/*
> + * Functions & macros implementing the PR_GET_FP_MODE & PR_SET_FP_MODE options
> + * to the prctl syscall.
> + */
> +extern int mips_get_process_fp_mode(struct task_struct *task);
> +extern int mips_set_process_fp_mode(struct task_struct *task,
> + unsigned int value);
> +
> +#define GET_FP_MODE(task) mips_get_process_fp_mode(task)
> +#define SET_FP_MODE(task,value) mips_set_process_fp_mode(task, value)
> +
> #endif /* _ASM_PROCESSOR_H */
> diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
> index eb76434..b732c0c 100644
> --- a/arch/mips/kernel/process.c
> +++ b/arch/mips/kernel/process.c
> @@ -25,6 +25,7 @@
> #include <linux/completion.h>
> #include <linux/kallsyms.h>
> #include <linux/random.h>
> +#include <linux/prctl.h>
>
> #include <asm/asm.h>
> #include <asm/bootinfo.h>
> @@ -550,3 +551,94 @@ void arch_trigger_all_cpu_backtrace(bool include_self)
> {
> smp_call_function(arch_dump_stack, NULL, 1);
> }
> +
> +int mips_get_process_fp_mode(struct task_struct *task)
> +{
> + int value = 0;
> +
> + if (!test_tsk_thread_flag(task, TIF_32BIT_FPREGS))
> + value |= PR_FP_MODE_FR;
> + if (test_tsk_thread_flag(task, TIF_HYBRID_FPREGS))
> + value |= PR_FP_MODE_FRE;
> +
> + return value;
> +}
> +
> +int mips_set_process_fp_mode(struct task_struct *task, unsigned int value)
> +{
> + const unsigned int known_bits = PR_FP_MODE_FR | PR_FP_MODE_FRE;
> + unsigned long switch_count;
> + struct task_struct *t;
> +
> + /* Check the value is valid */
> + if (value & ~known_bits)
> + return -EOPNOTSUPP;
> +
> + /* Avoid inadvertently triggering emulation */
> + if ((value & PR_FP_MODE_FR) && cpu_has_fpu &&
> + !(current_cpu_data.fpu_id & MIPS_FPIR_F64))
> + return -EOPNOTSUPP;
> + if ((value & PR_FP_MODE_FRE) && !cpu_has_fre)
> + return -EOPNOTSUPP;
> +
> + /* Save FP & vector context, then disable FPU & MSA */
> + if (task->signal == current->signal)
> + lose_fpu(1);
> +
> + /* Prevent any threads from obtaining live FP context */
> + atomic_set(&task->mm->context.fp_mode_switching, 1);
> + smp_mb__after_atomic();
> +
> + /*
> + * If there are multiple online CPUs then wait until all threads whose
> + * FP mode is about to change have been context switched. This approach
> + * allows us to only worry about whether an FP mode switch is in
> + * progress when FP is first used in a tasks time slice. Pretty much all
> + * of the mode switch overhead can thus be confined to cases where mode
> + * switches are actually occuring. That is, to here. However for the
> + * thread performing the mode switch it may take a while...
> + */
> + if (num_online_cpus() > 1) {
> + spin_lock_irq(&task->sighand->siglock);
> +
> + for_each_thread(task, t) {
> + if (t == current)
> + continue;
> +
> + switch_count = t->nvcsw + t->nivcsw;
> +
> + do {
> + spin_unlock_irq(&task->sighand->siglock);
> + cond_resched();
> + spin_lock_irq(&task->sighand->siglock);
> + } while ((t->nvcsw + t->nivcsw) == switch_count);
> + }
> +
> + spin_unlock_irq(&task->sighand->siglock);
> + }
> +
> + /*
> + * There are now no threads of the process with live FP context, so it
> + * is safe to proceed with the FP mode switch.
> + */
> + for_each_thread(task, t) {
> + /* Update desired FP register width */
> + if (value & PR_FP_MODE_FR) {
> + clear_tsk_thread_flag(t, TIF_32BIT_FPREGS);
> + } else {
> + set_tsk_thread_flag(t, TIF_32BIT_FPREGS);
> + clear_tsk_thread_flag(t, TIF_MSA_CTX_LIVE);
> + }
> +
> + /* Update desired FP single layout */
> + if (value & PR_FP_MODE_FRE)
> + set_tsk_thread_flag(t, TIF_HYBRID_FPREGS);
> + else
> + clear_tsk_thread_flag(t, TIF_HYBRID_FPREGS);
> + }
> +
> + /* Allow threads to use FP again */
> + atomic_set(&task->mm->context.fp_mode_switching, 0);
> +
> + return 0;
> +}
> diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
> index ad3d203..d5fbfb5 100644
> --- a/arch/mips/kernel/traps.c
> +++ b/arch/mips/kernel/traps.c
> @@ -1134,10 +1134,29 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
> return NOTIFY_OK;
> }
>
> +static int wait_on_fp_mode_switch(atomic_t *p)
> +{
> + /*
> + * The FP mode for this task is currently being switched. That may
> + * involve modifications to the format of this tasks FP context which
> + * make it unsafe to proceed with execution for the moment. Instead,
> + * schedule some other task.
> + */
> + schedule();
> + return 0;
> +}
> +
> static int enable_restore_fp_context(int msa)
> {
> int err, was_fpu_owner, prior_msa;
>
> + /*
> + * If an FP mode switch is currently underway, wait for it to
> + * complete before proceeding.
> + */
> + wait_on_atomic_t(¤t->mm->context.fp_mode_switching,
> + wait_on_fp_mode_switch, TASK_KILLABLE);
> +
> if (!used_math()) {
> /* First time FP context user. */
> preempt_disable();
> diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
> index 89f6350..31891d9 100644
> --- a/include/uapi/linux/prctl.h
> +++ b/include/uapi/linux/prctl.h
> @@ -185,4 +185,9 @@ struct prctl_mm_map {
> #define PR_MPX_ENABLE_MANAGEMENT 43
> #define PR_MPX_DISABLE_MANAGEMENT 44
>
> +#define PR_SET_FP_MODE 45
> +#define PR_GET_FP_MODE 46
> +# define PR_FP_MODE_FR (1 << 0) /* 64b FP registers */
> +# define PR_FP_MODE_FRE (1 << 1) /* 32b compatibility */
> +
> #endif /* _LINUX_PRCTL_H */
> diff --git a/kernel/sys.c b/kernel/sys.c
> index a8c9f5a..08b16bb 100644
> --- a/kernel/sys.c
> +++ b/kernel/sys.c
> @@ -97,6 +97,12 @@
> #ifndef MPX_DISABLE_MANAGEMENT
> # define MPX_DISABLE_MANAGEMENT(a) (-EINVAL)
> #endif
> +#ifndef GET_FP_MODE
> +# define GET_FP_MODE(a) (-EINVAL)
> +#endif
> +#ifndef SET_FP_MODE
> +# define SET_FP_MODE(a,b) (-EINVAL)
> +#endif
>
> /*
> * this is where the system-wide overflow UID and GID are defined, for
> @@ -2215,6 +2221,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
> case PR_MPX_DISABLE_MANAGEMENT:
> error = MPX_DISABLE_MANAGEMENT(me);
> break;
> + case PR_SET_FP_MODE:
> + error = SET_FP_MODE(me, arg2);
> + break;
> + case PR_GET_FP_MODE:
> + error = GET_FP_MODE(me);
> + break;
> default:
> error = -EINVAL;
> break;
>
--
markos
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH] MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS
@ 2015-01-13 13:12 ` Markos Chandras
0 siblings, 0 replies; 18+ messages in thread
From: Markos Chandras @ 2015-01-13 13:12 UTC (permalink / raw)
To: Paul Burton, linux-mips; +Cc: Matthew Fortune, LKML, linux-api
On 01/08/2015 12:17 PM, Paul Burton wrote:
> Userland code may be built using an ABI which permits linking to objects
> that have more restrictive floating point requirements. For example,
> userland code may be built to target the O32 FPXX ABI. Such code may be
> linked with other FPXX code, or code built for either one of the more
> restrictive FP32 or FP64. When linking with more restrictive code, the
> overall requirement of the process becomes that of the more restrictive
> code. The kernel has no way to know in advance which mode the process
> will need to be executed in, and indeed it may need to change during
> execution. The dynamic loader is the only code which will know the
> overall required mode, and so it needs to have a means to instruct the
> kernel to switch the FP mode of the process.
>
> This patch introduces 2 new options to the prctl syscall which provide
> such a capability. The FP mode of the process is represented as a
> simple bitmask combining a number of mode bits mirroring those present
> in the hardware. Userland can either retrieve the current FP mode of
> the process:
>
> mode = prctl(PR_GET_FP_MODE);
>
> or modify the current FP mode of the process:
>
> err = prctl(PR_SET_FP_MODE, new_mode);
>
> Signed-off-by: Paul Burton <paul.burton@imgtec.com>
> Cc: Matthew Fortune <matthew.fortune@imgtec.com>
> Cc: Markos Chandras <markos.chandras@imgtec.com>
Hi,
I think the "MIPS,prctl" in the title should be "MIPS: prctl"
I have also CC'd the LKML and the linux-api mailing lists since this
touches the kernel ABI with the new PR_[GS]ET_FP_MODE definitions.
(I intentionally leave the contents of the patch below so people can
comment on it)
> ---
> arch/mips/include/asm/mmu.h | 3 ++
> arch/mips/include/asm/mmu_context.h | 2 +
> arch/mips/include/asm/processor.h | 11 +++++
> arch/mips/kernel/process.c | 92 +++++++++++++++++++++++++++++++++++++
> arch/mips/kernel/traps.c | 19 ++++++++
> include/uapi/linux/prctl.h | 5 ++
> kernel/sys.c | 12 +++++
> 7 files changed, 144 insertions(+)
>
> diff --git a/arch/mips/include/asm/mmu.h b/arch/mips/include/asm/mmu.h
> index c436138..1afa1f9 100644
> --- a/arch/mips/include/asm/mmu.h
> +++ b/arch/mips/include/asm/mmu.h
> @@ -1,9 +1,12 @@
> #ifndef __ASM_MMU_H
> #define __ASM_MMU_H
>
> +#include <linux/atomic.h>
> +
> typedef struct {
> unsigned long asid[NR_CPUS];
> void *vdso;
> + atomic_t fp_mode_switching;
> } mm_context_t;
>
> #endif /* __ASM_MMU_H */
> diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h
> index 2f82568..87f1107 100644
> --- a/arch/mips/include/asm/mmu_context.h
> +++ b/arch/mips/include/asm/mmu_context.h
> @@ -132,6 +132,8 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm)
> for_each_possible_cpu(i)
> cpu_context(i, mm) = 0;
>
> + atomic_set(&mm->context.fp_mode_switching, 0);
> +
> return 0;
> }
>
> diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
> index f1df4cb..9daa386 100644
> --- a/arch/mips/include/asm/processor.h
> +++ b/arch/mips/include/asm/processor.h
> @@ -399,4 +399,15 @@ unsigned long get_wchan(struct task_struct *p);
>
> #endif
>
> +/*
> + * Functions & macros implementing the PR_GET_FP_MODE & PR_SET_FP_MODE options
> + * to the prctl syscall.
> + */
> +extern int mips_get_process_fp_mode(struct task_struct *task);
> +extern int mips_set_process_fp_mode(struct task_struct *task,
> + unsigned int value);
> +
> +#define GET_FP_MODE(task) mips_get_process_fp_mode(task)
> +#define SET_FP_MODE(task,value) mips_set_process_fp_mode(task, value)
> +
> #endif /* _ASM_PROCESSOR_H */
> diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
> index eb76434..b732c0c 100644
> --- a/arch/mips/kernel/process.c
> +++ b/arch/mips/kernel/process.c
> @@ -25,6 +25,7 @@
> #include <linux/completion.h>
> #include <linux/kallsyms.h>
> #include <linux/random.h>
> +#include <linux/prctl.h>
>
> #include <asm/asm.h>
> #include <asm/bootinfo.h>
> @@ -550,3 +551,94 @@ void arch_trigger_all_cpu_backtrace(bool include_self)
> {
> smp_call_function(arch_dump_stack, NULL, 1);
> }
> +
> +int mips_get_process_fp_mode(struct task_struct *task)
> +{
> + int value = 0;
> +
> + if (!test_tsk_thread_flag(task, TIF_32BIT_FPREGS))
> + value |= PR_FP_MODE_FR;
> + if (test_tsk_thread_flag(task, TIF_HYBRID_FPREGS))
> + value |= PR_FP_MODE_FRE;
> +
> + return value;
> +}
> +
> +int mips_set_process_fp_mode(struct task_struct *task, unsigned int value)
> +{
> + const unsigned int known_bits = PR_FP_MODE_FR | PR_FP_MODE_FRE;
> + unsigned long switch_count;
> + struct task_struct *t;
> +
> + /* Check the value is valid */
> + if (value & ~known_bits)
> + return -EOPNOTSUPP;
> +
> + /* Avoid inadvertently triggering emulation */
> + if ((value & PR_FP_MODE_FR) && cpu_has_fpu &&
> + !(current_cpu_data.fpu_id & MIPS_FPIR_F64))
> + return -EOPNOTSUPP;
> + if ((value & PR_FP_MODE_FRE) && !cpu_has_fre)
> + return -EOPNOTSUPP;
> +
> + /* Save FP & vector context, then disable FPU & MSA */
> + if (task->signal == current->signal)
> + lose_fpu(1);
> +
> + /* Prevent any threads from obtaining live FP context */
> + atomic_set(&task->mm->context.fp_mode_switching, 1);
> + smp_mb__after_atomic();
> +
> + /*
> + * If there are multiple online CPUs then wait until all threads whose
> + * FP mode is about to change have been context switched. This approach
> + * allows us to only worry about whether an FP mode switch is in
> + * progress when FP is first used in a tasks time slice. Pretty much all
> + * of the mode switch overhead can thus be confined to cases where mode
> + * switches are actually occuring. That is, to here. However for the
> + * thread performing the mode switch it may take a while...
> + */
> + if (num_online_cpus() > 1) {
> + spin_lock_irq(&task->sighand->siglock);
> +
> + for_each_thread(task, t) {
> + if (t == current)
> + continue;
> +
> + switch_count = t->nvcsw + t->nivcsw;
> +
> + do {
> + spin_unlock_irq(&task->sighand->siglock);
> + cond_resched();
> + spin_lock_irq(&task->sighand->siglock);
> + } while ((t->nvcsw + t->nivcsw) == switch_count);
> + }
> +
> + spin_unlock_irq(&task->sighand->siglock);
> + }
> +
> + /*
> + * There are now no threads of the process with live FP context, so it
> + * is safe to proceed with the FP mode switch.
> + */
> + for_each_thread(task, t) {
> + /* Update desired FP register width */
> + if (value & PR_FP_MODE_FR) {
> + clear_tsk_thread_flag(t, TIF_32BIT_FPREGS);
> + } else {
> + set_tsk_thread_flag(t, TIF_32BIT_FPREGS);
> + clear_tsk_thread_flag(t, TIF_MSA_CTX_LIVE);
> + }
> +
> + /* Update desired FP single layout */
> + if (value & PR_FP_MODE_FRE)
> + set_tsk_thread_flag(t, TIF_HYBRID_FPREGS);
> + else
> + clear_tsk_thread_flag(t, TIF_HYBRID_FPREGS);
> + }
> +
> + /* Allow threads to use FP again */
> + atomic_set(&task->mm->context.fp_mode_switching, 0);
> +
> + return 0;
> +}
> diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
> index ad3d203..d5fbfb5 100644
> --- a/arch/mips/kernel/traps.c
> +++ b/arch/mips/kernel/traps.c
> @@ -1134,10 +1134,29 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
> return NOTIFY_OK;
> }
>
> +static int wait_on_fp_mode_switch(atomic_t *p)
> +{
> + /*
> + * The FP mode for this task is currently being switched. That may
> + * involve modifications to the format of this tasks FP context which
> + * make it unsafe to proceed with execution for the moment. Instead,
> + * schedule some other task.
> + */
> + schedule();
> + return 0;
> +}
> +
> static int enable_restore_fp_context(int msa)
> {
> int err, was_fpu_owner, prior_msa;
>
> + /*
> + * If an FP mode switch is currently underway, wait for it to
> + * complete before proceeding.
> + */
> + wait_on_atomic_t(¤t->mm->context.fp_mode_switching,
> + wait_on_fp_mode_switch, TASK_KILLABLE);
> +
> if (!used_math()) {
> /* First time FP context user. */
> preempt_disable();
> diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
> index 89f6350..31891d9 100644
> --- a/include/uapi/linux/prctl.h
> +++ b/include/uapi/linux/prctl.h
> @@ -185,4 +185,9 @@ struct prctl_mm_map {
> #define PR_MPX_ENABLE_MANAGEMENT 43
> #define PR_MPX_DISABLE_MANAGEMENT 44
>
> +#define PR_SET_FP_MODE 45
> +#define PR_GET_FP_MODE 46
> +# define PR_FP_MODE_FR (1 << 0) /* 64b FP registers */
> +# define PR_FP_MODE_FRE (1 << 1) /* 32b compatibility */
> +
> #endif /* _LINUX_PRCTL_H */
> diff --git a/kernel/sys.c b/kernel/sys.c
> index a8c9f5a..08b16bb 100644
> --- a/kernel/sys.c
> +++ b/kernel/sys.c
> @@ -97,6 +97,12 @@
> #ifndef MPX_DISABLE_MANAGEMENT
> # define MPX_DISABLE_MANAGEMENT(a) (-EINVAL)
> #endif
> +#ifndef GET_FP_MODE
> +# define GET_FP_MODE(a) (-EINVAL)
> +#endif
> +#ifndef SET_FP_MODE
> +# define SET_FP_MODE(a,b) (-EINVAL)
> +#endif
>
> /*
> * this is where the system-wide overflow UID and GID are defined, for
> @@ -2215,6 +2221,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
> case PR_MPX_DISABLE_MANAGEMENT:
> error = MPX_DISABLE_MANAGEMENT(me);
> break;
> + case PR_SET_FP_MODE:
> + error = SET_FP_MODE(me, arg2);
> + break;
> + case PR_GET_FP_MODE:
> + error = GET_FP_MODE(me);
> + break;
> default:
> error = -EINVAL;
> break;
>
--
markos
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH] MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS
2015-01-13 13:12 ` Markos Chandras
(?)
@ 2015-01-16 15:43 ` Markos Chandras
-1 siblings, 0 replies; 18+ messages in thread
From: Markos Chandras @ 2015-01-16 15:43 UTC (permalink / raw)
To: Paul Burton, linux-mips-6z/3iImG2C8G8FEW9MqTrA
Cc: Matthew Fortune, LKML, linux-api-u79uwXL29TY76Z2rM5mHXA
On 01/13/2015 01:12 PM, Markos Chandras wrote:
> On 01/08/2015 12:17 PM, Paul Burton wrote:
>> Userland code may be built using an ABI which permits linking to objects
>> that have more restrictive floating point requirements. For example,
>> userland code may be built to target the O32 FPXX ABI. Such code may be
>> linked with other FPXX code, or code built for either one of the more
>> restrictive FP32 or FP64. When linking with more restrictive code, the
>> overall requirement of the process becomes that of the more restrictive
>> code. The kernel has no way to know in advance which mode the process
>> will need to be executed in, and indeed it may need to change during
>> execution. The dynamic loader is the only code which will know the
>> overall required mode, and so it needs to have a means to instruct the
>> kernel to switch the FP mode of the process.
>>
>> This patch introduces 2 new options to the prctl syscall which provide
>> such a capability. The FP mode of the process is represented as a
>> simple bitmask combining a number of mode bits mirroring those present
>> in the hardware. Userland can either retrieve the current FP mode of
>> the process:
>>
>> mode = prctl(PR_GET_FP_MODE);
>> [...]
>> +int mips_set_process_fp_mode(struct task_struct *task, unsigned int value)
>> +{
>> + const unsigned int known_bits = PR_FP_MODE_FR | PR_FP_MODE_FRE;
>> + unsigned long switch_count;
>> + struct task_struct *t;
>> +
>> + /* Check the value is valid */
>> + if (value & ~known_bits)
>> + return -EOPNOTSUPP;
>> +
>> + /* Avoid inadvertently triggering emulation */
>> + if ((value & PR_FP_MODE_FR) && cpu_has_fpu &&
>> + !(current_cpu_data.fpu_id & MIPS_FPIR_F64))
>> + return -EOPNOTSUPP;
>> + if ((value & PR_FP_MODE_FRE) && !cpu_has_fre)
>> + return -EOPNOTSUPP;
>> +
Hi Paul,
Do you think you can address this[1] suggestion by Matthew in this patch
since this hasn't been merged yet? Thanks
[1] http://www.linux-mips.org/archives/linux-mips/2015-01/msg00265.html
--
markos
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH] MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS
@ 2015-01-16 15:43 ` Markos Chandras
0 siblings, 0 replies; 18+ messages in thread
From: Markos Chandras @ 2015-01-16 15:43 UTC (permalink / raw)
To: Paul Burton, linux-mips; +Cc: Matthew Fortune, LKML, linux-api
On 01/13/2015 01:12 PM, Markos Chandras wrote:
> On 01/08/2015 12:17 PM, Paul Burton wrote:
>> Userland code may be built using an ABI which permits linking to objects
>> that have more restrictive floating point requirements. For example,
>> userland code may be built to target the O32 FPXX ABI. Such code may be
>> linked with other FPXX code, or code built for either one of the more
>> restrictive FP32 or FP64. When linking with more restrictive code, the
>> overall requirement of the process becomes that of the more restrictive
>> code. The kernel has no way to know in advance which mode the process
>> will need to be executed in, and indeed it may need to change during
>> execution. The dynamic loader is the only code which will know the
>> overall required mode, and so it needs to have a means to instruct the
>> kernel to switch the FP mode of the process.
>>
>> This patch introduces 2 new options to the prctl syscall which provide
>> such a capability. The FP mode of the process is represented as a
>> simple bitmask combining a number of mode bits mirroring those present
>> in the hardware. Userland can either retrieve the current FP mode of
>> the process:
>>
>> mode = prctl(PR_GET_FP_MODE);
>> [...]
>> +int mips_set_process_fp_mode(struct task_struct *task, unsigned int value)
>> +{
>> + const unsigned int known_bits = PR_FP_MODE_FR | PR_FP_MODE_FRE;
>> + unsigned long switch_count;
>> + struct task_struct *t;
>> +
>> + /* Check the value is valid */
>> + if (value & ~known_bits)
>> + return -EOPNOTSUPP;
>> +
>> + /* Avoid inadvertently triggering emulation */
>> + if ((value & PR_FP_MODE_FR) && cpu_has_fpu &&
>> + !(current_cpu_data.fpu_id & MIPS_FPIR_F64))
>> + return -EOPNOTSUPP;
>> + if ((value & PR_FP_MODE_FRE) && !cpu_has_fre)
>> + return -EOPNOTSUPP;
>> +
Hi Paul,
Do you think you can address this[1] suggestion by Matthew in this patch
since this hasn't been merged yet? Thanks
[1] http://www.linux-mips.org/archives/linux-mips/2015-01/msg00265.html
--
markos
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH] MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS
@ 2015-01-16 15:43 ` Markos Chandras
0 siblings, 0 replies; 18+ messages in thread
From: Markos Chandras @ 2015-01-16 15:43 UTC (permalink / raw)
To: Paul Burton, linux-mips; +Cc: Matthew Fortune, LKML, linux-api
On 01/13/2015 01:12 PM, Markos Chandras wrote:
> On 01/08/2015 12:17 PM, Paul Burton wrote:
>> Userland code may be built using an ABI which permits linking to objects
>> that have more restrictive floating point requirements. For example,
>> userland code may be built to target the O32 FPXX ABI. Such code may be
>> linked with other FPXX code, or code built for either one of the more
>> restrictive FP32 or FP64. When linking with more restrictive code, the
>> overall requirement of the process becomes that of the more restrictive
>> code. The kernel has no way to know in advance which mode the process
>> will need to be executed in, and indeed it may need to change during
>> execution. The dynamic loader is the only code which will know the
>> overall required mode, and so it needs to have a means to instruct the
>> kernel to switch the FP mode of the process.
>>
>> This patch introduces 2 new options to the prctl syscall which provide
>> such a capability. The FP mode of the process is represented as a
>> simple bitmask combining a number of mode bits mirroring those present
>> in the hardware. Userland can either retrieve the current FP mode of
>> the process:
>>
>> mode = prctl(PR_GET_FP_MODE);
>> [...]
>> +int mips_set_process_fp_mode(struct task_struct *task, unsigned int value)
>> +{
>> + const unsigned int known_bits = PR_FP_MODE_FR | PR_FP_MODE_FRE;
>> + unsigned long switch_count;
>> + struct task_struct *t;
>> +
>> + /* Check the value is valid */
>> + if (value & ~known_bits)
>> + return -EOPNOTSUPP;
>> +
>> + /* Avoid inadvertently triggering emulation */
>> + if ((value & PR_FP_MODE_FR) && cpu_has_fpu &&
>> + !(current_cpu_data.fpu_id & MIPS_FPIR_F64))
>> + return -EOPNOTSUPP;
>> + if ((value & PR_FP_MODE_FRE) && !cpu_has_fre)
>> + return -EOPNOTSUPP;
>> +
Hi Paul,
Do you think you can address this[1] suggestion by Matthew in this patch
since this hasn't been merged yet? Thanks
[1] http://www.linux-mips.org/archives/linux-mips/2015-01/msg00265.html
--
markos
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH] MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS
2015-01-13 13:12 ` Markos Chandras
(?)
@ 2015-01-18 21:47 ` Paul Burton
-1 siblings, 0 replies; 18+ messages in thread
From: Paul Burton @ 2015-01-18 21:47 UTC (permalink / raw)
To: Markos Chandras
Cc: linux-mips-6z/3iImG2C8G8FEW9MqTrA, Matthew Fortune, LKML,
linux-api-u79uwXL29TY76Z2rM5mHXA
On Tue, Jan 13, 2015 at 01:12:22PM +0000, Markos Chandras wrote:
> Hi,
>
> I think the "MIPS,prctl" in the title should be "MIPS: prctl"
I used the comma to denote a list - that is, this change affects both
MIPS & the generic prctl code. To me your "MIPS: prctl" suggestion would
indicate that the changes are confined to arch/mips.
> I have also CC'd the LKML and the linux-api mailing lists since this
> touches the kernel ABI with the new PR_[GS]ET_FP_MODE definitions.
Thanks,
Paul
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH] MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS
@ 2015-01-18 21:47 ` Paul Burton
0 siblings, 0 replies; 18+ messages in thread
From: Paul Burton @ 2015-01-18 21:47 UTC (permalink / raw)
To: Markos Chandras; +Cc: linux-mips, Matthew Fortune, LKML, linux-api
On Tue, Jan 13, 2015 at 01:12:22PM +0000, Markos Chandras wrote:
> Hi,
>
> I think the "MIPS,prctl" in the title should be "MIPS: prctl"
I used the comma to denote a list - that is, this change affects both
MIPS & the generic prctl code. To me your "MIPS: prctl" suggestion would
indicate that the changes are confined to arch/mips.
> I have also CC'd the LKML and the linux-api mailing lists since this
> touches the kernel ABI with the new PR_[GS]ET_FP_MODE definitions.
Thanks,
Paul
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH] MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS
@ 2015-01-18 21:47 ` Paul Burton
0 siblings, 0 replies; 18+ messages in thread
From: Paul Burton @ 2015-01-18 21:47 UTC (permalink / raw)
To: Markos Chandras; +Cc: linux-mips, Matthew Fortune, LKML, linux-api
On Tue, Jan 13, 2015 at 01:12:22PM +0000, Markos Chandras wrote:
> Hi,
>
> I think the "MIPS,prctl" in the title should be "MIPS: prctl"
I used the comma to denote a list - that is, this change affects both
MIPS & the generic prctl code. To me your "MIPS: prctl" suggestion would
indicate that the changes are confined to arch/mips.
> I have also CC'd the LKML and the linux-api mailing lists since this
> touches the kernel ABI with the new PR_[GS]ET_FP_MODE definitions.
Thanks,
Paul
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2015-01-18 21:48 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-01-08 12:17 [PATCH] MIPS,prctl: add PR_[GS]ET_FP_MODE prctl options for MIPS Paul Burton
2015-01-08 12:17 ` Paul Burton
2015-01-08 12:54 ` Matthew Fortune
2015-01-09 2:25 ` Leonid Yegoshin
2015-01-09 2:25 ` Leonid Yegoshin
2015-01-09 8:34 ` Matthew Fortune
2015-01-09 18:42 ` Leonid Yegoshin
[not found] ` <54B024AA.1020400@imgtec.com>
2015-01-09 21:25 ` Matthew Fortune
2015-01-09 21:25 ` Matthew Fortune
[not found] ` <1420719457-690-1-git-send-email-paul.burton-1AXoQHu6uovQT0dZR+AlfA@public.gmane.org>
2015-01-13 13:12 ` [PATCH] " Markos Chandras
2015-01-13 13:12 ` Markos Chandras
2015-01-13 13:12 ` Markos Chandras
[not found] ` <54B519B6.5040604-1AXoQHu6uovQT0dZR+AlfA@public.gmane.org>
2015-01-16 15:43 ` Markos Chandras
2015-01-16 15:43 ` Markos Chandras
2015-01-16 15:43 ` Markos Chandras
2015-01-18 21:47 ` Paul Burton
2015-01-18 21:47 ` Paul Burton
2015-01-18 21:47 ` Paul Burton
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.