All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/(8+2)] MIPS: IEEE Std 754-2008 features
@ 2015-11-13  0:46 ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:46 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Hi,

 As many of you have been aware it has been a long practice for software
using IEEE 754 floating-point arithmetic run on MIPS processors to use an
encoding of Not-a-Number (NaN) data different to one used by software run
on other processors.  And as of IEEE 754-2008 revision [1] this encoding
does not follow one recommended in the standard, as specified in section
6.2.1, where it is stated that quiet NaNs should have the first bit (d1)
of their significand set to 1 while signalling NaNs should have that bit
set to 0, but MIPS software interprets the two bits in the opposite
manner.

 As from revision 3.50 [2][3] the MIPS Architecture provides for 
processors that support the IEEE 754-2008 preferred NaN encoding format. 
As the two formats (further referred to as "legacy NaN" and "2008 NaN") 
are incompatible to each other, the run-time environment has to provide 
support for the two formats to help people avoid using incompatible binary 
modules.  Here is the Linux kernel part.

 These are 8 changes comprising the actual feature and a set of 2 extra 
patches -- a code structure clean-up for ELF personality macros, and a 
proposal to make sNaN bit pattern propagation more in line with the 
current version of the said standard even for legacy-NaN implementations.

 The complementing glibc dynamic loader part has been posted here: 
<http://sourceware.org/ml/libc-ports/2013-09/msg00048.html> and included 
in FSF glibc <git://sourceware.org/git/glibc.git> with commit 9c21573c.

 References:

[1] "IEEE Standard for Floating-Point Arithmetic", IEEE Computer Society,
    IEEE Std 754-2008, 29 August 2008

[2] "MIPS Architecture For Programmers, Volume I-A: Introduction to the
    MIPS32 Architecture", MIPS Technologies, Inc., Document Number:
    MD00082, Revision 3.50, September 20, 2012

[3] "MIPS Architecture For Programmers, Volume I-A: Introduction to the
    MIPS64 Architecture", MIPS Technologies, Inc., Document Number:
    MD00083, Revision 3.50, September 20, 2012

  Maciej

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 0/(8+2)] MIPS: IEEE Std 754-2008 features
@ 2015-11-13  0:46 ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:46 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Hi,

 As many of you have been aware it has been a long practice for software
using IEEE 754 floating-point arithmetic run on MIPS processors to use an
encoding of Not-a-Number (NaN) data different to one used by software run
on other processors.  And as of IEEE 754-2008 revision [1] this encoding
does not follow one recommended in the standard, as specified in section
6.2.1, where it is stated that quiet NaNs should have the first bit (d1)
of their significand set to 1 while signalling NaNs should have that bit
set to 0, but MIPS software interprets the two bits in the opposite
manner.

 As from revision 3.50 [2][3] the MIPS Architecture provides for 
processors that support the IEEE 754-2008 preferred NaN encoding format. 
As the two formats (further referred to as "legacy NaN" and "2008 NaN") 
are incompatible to each other, the run-time environment has to provide 
support for the two formats to help people avoid using incompatible binary 
modules.  Here is the Linux kernel part.

 These are 8 changes comprising the actual feature and a set of 2 extra 
patches -- a code structure clean-up for ELF personality macros, and a 
proposal to make sNaN bit pattern propagation more in line with the 
current version of the said standard even for legacy-NaN implementations.

 The complementing glibc dynamic loader part has been posted here: 
<http://sourceware.org/ml/libc-ports/2013-09/msg00048.html> and included 
in FSF glibc <git://sourceware.org/git/glibc.git> with commit 9c21573c.

 References:

[1] "IEEE Standard for Floating-Point Arithmetic", IEEE Computer Society,
    IEEE Std 754-2008, 29 August 2008

[2] "MIPS Architecture For Programmers, Volume I-A: Introduction to the
    MIPS32 Architecture", MIPS Technologies, Inc., Document Number:
    MD00082, Revision 3.50, September 20, 2012

[3] "MIPS Architecture For Programmers, Volume I-A: Introduction to the
    MIPS64 Architecture", MIPS Technologies, Inc., Document Number:
    MD00083, Revision 3.50, September 20, 2012

  Maciej

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 1/8] MIPS: Use a union to access the ELF file header
@ 2015-11-13  0:46   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:46 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Rewrite `arch_elf_pt_proc' and `arch_check_elf' using a union to access 
the ELF file header.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
linux-mips-elf-ehdr.diff
Index: linux-sfr-test/arch/mips/kernel/elf.c
===================================================================
--- linux-sfr-test.orig/arch/mips/kernel/elf.c	2015-09-04 22:46:08.374274000 +0100
+++ linux-sfr-test/arch/mips/kernel/elf.c	2015-09-04 22:47:56.448146000 +0100
@@ -68,15 +68,23 @@ static struct mode_req none_req = { true
 int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf,
 		     bool is_interp, struct arch_elf_state *state)
 {
-	struct elf32_hdr *ehdr32 = _ehdr;
+	union {
+		struct elf32_hdr e32;
+		struct elf64_hdr e64;
+	} *ehdr = _ehdr;
 	struct elf32_phdr *phdr32 = _phdr;
 	struct elf64_phdr *phdr64 = _phdr;
 	struct mips_elf_abiflags_v0 abiflags;
+	bool elf32;
+	u32 flags;
 	int ret;
 
+	elf32 = ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32;
+	flags = elf32 ? ehdr->e32.e_flags : ehdr->e64.e_flags;
+
 	/* Lets see if this is an O32 ELF */
-	if (ehdr32->e_ident[EI_CLASS] == ELFCLASS32) {
-		if (ehdr32->e_flags & EF_MIPS_FP64) {
+	if (elf32) {
+		if (flags & EF_MIPS_FP64) {
 			/*
 			 * Set MIPS_ABI_FP_OLD_64 for EF_MIPS_FP64. We will override it
 			 * later if needed
@@ -123,10 +131,17 @@ int arch_elf_pt_proc(void *_ehdr, void *
 int arch_check_elf(void *_ehdr, bool has_interpreter,
 		   struct arch_elf_state *state)
 {
-	struct elf32_hdr *ehdr = _ehdr;
+	union {
+		struct elf32_hdr e32;
+		struct elf64_hdr e64;
+	} *ehdr = _ehdr;
 	struct mode_req prog_req, interp_req;
 	int fp_abi, interp_fp_abi, abi0, abi1, max_abi;
-	bool is_mips64;
+	bool elf32;
+	u32 flags;
+
+	elf32 = ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32;
+	flags = elf32 ? ehdr->e32.e_flags : ehdr->e64.e_flags;
 
 	if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
 		return 0;
@@ -142,21 +157,18 @@ int arch_check_elf(void *_ehdr, bool has
 		abi0 = abi1 = fp_abi;
 	}
 
-	is_mips64 = (ehdr->e_ident[EI_CLASS] == ELFCLASS64) ||
-		    (ehdr->e_flags & EF_MIPS_ABI2);
+	if (elf32 && !(flags & EF_MIPS_ABI2)) {
+		/* Default to a mode capable of running code expecting FR=0 */
+		state->overall_fp_mode = cpu_has_mips_r6 ? FP_FRE : FP_FR0;
 
-	if (is_mips64) {
+		/* Allow all ABIs we know about */
+		max_abi = MIPS_ABI_FP_64A;
+	} else {
 		/* MIPS64 code always uses FR=1, thus the default is easy */
 		state->overall_fp_mode = FP_FR1;
 
 		/* Disallow access to the various FPXX & FP64 ABIs */
 		max_abi = MIPS_ABI_FP_SOFT;
-	} else {
-		/* Default to a mode capable of running code expecting FR=0 */
-		state->overall_fp_mode = cpu_has_mips_r6 ? FP_FRE : FP_FR0;
-
-		/* Allow all ABIs we know about */
-		max_abi = MIPS_ABI_FP_64A;
 	}
 
 	if ((abi0 > max_abi && abi0 != MIPS_ABI_FP_UNKNOWN) ||

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 1/8] MIPS: Use a union to access the ELF file header
@ 2015-11-13  0:46   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:46 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Rewrite `arch_elf_pt_proc' and `arch_check_elf' using a union to access 
the ELF file header.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
linux-mips-elf-ehdr.diff
Index: linux-sfr-test/arch/mips/kernel/elf.c
===================================================================
--- linux-sfr-test.orig/arch/mips/kernel/elf.c	2015-09-04 22:46:08.374274000 +0100
+++ linux-sfr-test/arch/mips/kernel/elf.c	2015-09-04 22:47:56.448146000 +0100
@@ -68,15 +68,23 @@ static struct mode_req none_req = { true
 int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf,
 		     bool is_interp, struct arch_elf_state *state)
 {
-	struct elf32_hdr *ehdr32 = _ehdr;
+	union {
+		struct elf32_hdr e32;
+		struct elf64_hdr e64;
+	} *ehdr = _ehdr;
 	struct elf32_phdr *phdr32 = _phdr;
 	struct elf64_phdr *phdr64 = _phdr;
 	struct mips_elf_abiflags_v0 abiflags;
+	bool elf32;
+	u32 flags;
 	int ret;
 
+	elf32 = ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32;
+	flags = elf32 ? ehdr->e32.e_flags : ehdr->e64.e_flags;
+
 	/* Lets see if this is an O32 ELF */
-	if (ehdr32->e_ident[EI_CLASS] == ELFCLASS32) {
-		if (ehdr32->e_flags & EF_MIPS_FP64) {
+	if (elf32) {
+		if (flags & EF_MIPS_FP64) {
 			/*
 			 * Set MIPS_ABI_FP_OLD_64 for EF_MIPS_FP64. We will override it
 			 * later if needed
@@ -123,10 +131,17 @@ int arch_elf_pt_proc(void *_ehdr, void *
 int arch_check_elf(void *_ehdr, bool has_interpreter,
 		   struct arch_elf_state *state)
 {
-	struct elf32_hdr *ehdr = _ehdr;
+	union {
+		struct elf32_hdr e32;
+		struct elf64_hdr e64;
+	} *ehdr = _ehdr;
 	struct mode_req prog_req, interp_req;
 	int fp_abi, interp_fp_abi, abi0, abi1, max_abi;
-	bool is_mips64;
+	bool elf32;
+	u32 flags;
+
+	elf32 = ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32;
+	flags = elf32 ? ehdr->e32.e_flags : ehdr->e64.e_flags;
 
 	if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
 		return 0;
@@ -142,21 +157,18 @@ int arch_check_elf(void *_ehdr, bool has
 		abi0 = abi1 = fp_abi;
 	}
 
-	is_mips64 = (ehdr->e_ident[EI_CLASS] == ELFCLASS64) ||
-		    (ehdr->e_flags & EF_MIPS_ABI2);
+	if (elf32 && !(flags & EF_MIPS_ABI2)) {
+		/* Default to a mode capable of running code expecting FR=0 */
+		state->overall_fp_mode = cpu_has_mips_r6 ? FP_FRE : FP_FR0;
 
-	if (is_mips64) {
+		/* Allow all ABIs we know about */
+		max_abi = MIPS_ABI_FP_64A;
+	} else {
 		/* MIPS64 code always uses FR=1, thus the default is easy */
 		state->overall_fp_mode = FP_FR1;
 
 		/* Disallow access to the various FPXX & FP64 ABIs */
 		max_abi = MIPS_ABI_FP_SOFT;
-	} else {
-		/* Default to a mode capable of running code expecting FR=0 */
-		state->overall_fp_mode = cpu_has_mips_r6 ? FP_FRE : FP_FR0;
-
-		/* Allow all ABIs we know about */
-		max_abi = MIPS_ABI_FP_64A;
 	}
 
 	if ((abi0 > max_abi && abi0 != MIPS_ABI_FP_UNKNOWN) ||

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 2/8] MIPS: Define the legacy-NaN and 2008-NaN features
@ 2015-11-13  0:46   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:46 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Allocate CPU option bits and define macros for the legacy-NaN and 
2008-NaN IEEE Std 754 MIPS architecture features.  Unconditionally mark 
the legacy-NaN feature as present across hardware and emulated 
floating-point configurations.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
linux-mips-nan-legacy.diff
Index: linux-sfr-test/arch/mips/include/asm/cpu-features.h
===================================================================
--- linux-sfr-test.orig/arch/mips/include/asm/cpu-features.h	2015-10-07 19:33:20.000000000 +0100
+++ linux-sfr-test/arch/mips/include/asm/cpu-features.h	2015-10-07 20:48:14.828556000 +0100
@@ -414,4 +414,11 @@
 # define cpu_has_small_pages	(cpu_data[0].options & MIPS_CPU_SP)
 #endif
 
+#ifndef cpu_has_nan_legacy
+#define cpu_has_nan_legacy	(cpu_data[0].options & MIPS_CPU_NAN_LEGACY)
+#endif
+#ifndef cpu_has_nan_2008
+#define cpu_has_nan_2008	(cpu_data[0].options & MIPS_CPU_NAN_2008)
+#endif
+
 #endif /* __ASM_CPU_FEATURES_H */
Index: linux-sfr-test/arch/mips/include/asm/cpu.h
===================================================================
--- linux-sfr-test.orig/arch/mips/include/asm/cpu.h	2015-10-07 19:33:20.000000000 +0100
+++ linux-sfr-test/arch/mips/include/asm/cpu.h	2015-10-07 20:48:14.831542000 +0100
@@ -386,6 +386,8 @@ enum cpu_type_enum {
 #define MIPS_CPU_BP_GHIST	0x8000000000ull /* R12K+ Branch Prediction Global History */
 #define MIPS_CPU_SP		0x10000000000ull /* Small (1KB) page support */
 #define MIPS_CPU_FTLB		0x20000000000ull /* CPU has Fixed-page-size TLB */
+#define MIPS_CPU_NAN_LEGACY	0x40000000000ull /* Legacy NaN implemented */
+#define MIPS_CPU_NAN_2008	0x80000000000ull /* 2008 NaN implemented */
 
 /*
  * CPU ASE encodings
Index: linux-sfr-test/arch/mips/kernel/cpu-probe.c
===================================================================
--- linux-sfr-test.orig/arch/mips/kernel/cpu-probe.c	2015-10-07 19:33:20.000000000 +0100
+++ linux-sfr-test/arch/mips/kernel/cpu-probe.c	2015-10-07 20:48:14.836528000 +0100
@@ -137,6 +137,7 @@ static void cpu_set_fpu_opts(struct cpui
 	}
 
 	cpu_set_fpu_fcsr_mask(c);
+	c->options |= MIPS_CPU_NAN_LEGACY;
 }
 
 /*
@@ -147,6 +148,7 @@ static void cpu_set_nofpu_opts(struct cp
 	c->options &= ~MIPS_CPU_FPU;
 	c->fpu_msk31 = mips_nofpu_msk31;
 
+	c->options |= MIPS_CPU_NAN_LEGACY;
 	cpu_set_nofpu_id(c);
 }
 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 2/8] MIPS: Define the legacy-NaN and 2008-NaN features
@ 2015-11-13  0:46   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:46 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Allocate CPU option bits and define macros for the legacy-NaN and 
2008-NaN IEEE Std 754 MIPS architecture features.  Unconditionally mark 
the legacy-NaN feature as present across hardware and emulated 
floating-point configurations.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
linux-mips-nan-legacy.diff
Index: linux-sfr-test/arch/mips/include/asm/cpu-features.h
===================================================================
--- linux-sfr-test.orig/arch/mips/include/asm/cpu-features.h	2015-10-07 19:33:20.000000000 +0100
+++ linux-sfr-test/arch/mips/include/asm/cpu-features.h	2015-10-07 20:48:14.828556000 +0100
@@ -414,4 +414,11 @@
 # define cpu_has_small_pages	(cpu_data[0].options & MIPS_CPU_SP)
 #endif
 
+#ifndef cpu_has_nan_legacy
+#define cpu_has_nan_legacy	(cpu_data[0].options & MIPS_CPU_NAN_LEGACY)
+#endif
+#ifndef cpu_has_nan_2008
+#define cpu_has_nan_2008	(cpu_data[0].options & MIPS_CPU_NAN_2008)
+#endif
+
 #endif /* __ASM_CPU_FEATURES_H */
Index: linux-sfr-test/arch/mips/include/asm/cpu.h
===================================================================
--- linux-sfr-test.orig/arch/mips/include/asm/cpu.h	2015-10-07 19:33:20.000000000 +0100
+++ linux-sfr-test/arch/mips/include/asm/cpu.h	2015-10-07 20:48:14.831542000 +0100
@@ -386,6 +386,8 @@ enum cpu_type_enum {
 #define MIPS_CPU_BP_GHIST	0x8000000000ull /* R12K+ Branch Prediction Global History */
 #define MIPS_CPU_SP		0x10000000000ull /* Small (1KB) page support */
 #define MIPS_CPU_FTLB		0x20000000000ull /* CPU has Fixed-page-size TLB */
+#define MIPS_CPU_NAN_LEGACY	0x40000000000ull /* Legacy NaN implemented */
+#define MIPS_CPU_NAN_2008	0x80000000000ull /* 2008 NaN implemented */
 
 /*
  * CPU ASE encodings
Index: linux-sfr-test/arch/mips/kernel/cpu-probe.c
===================================================================
--- linux-sfr-test.orig/arch/mips/kernel/cpu-probe.c	2015-10-07 19:33:20.000000000 +0100
+++ linux-sfr-test/arch/mips/kernel/cpu-probe.c	2015-10-07 20:48:14.836528000 +0100
@@ -137,6 +137,7 @@ static void cpu_set_fpu_opts(struct cpui
 	}
 
 	cpu_set_fpu_fcsr_mask(c);
+	c->options |= MIPS_CPU_NAN_LEGACY;
 }
 
 /*
@@ -147,6 +148,7 @@ static void cpu_set_nofpu_opts(struct cp
 	c->options &= ~MIPS_CPU_FPU;
 	c->fpu_msk31 = mips_nofpu_msk31;
 
+	c->options |= MIPS_CPU_NAN_LEGACY;
 	cpu_set_nofpu_id(c);
 }
 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 3/8] MIPS: math-emu: Add IEEE Std 754-2008 ABS.fmt and NEG.fmt emulation
@ 2015-11-13  0:47   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:47 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Implement IEEE Std 754-2008 non-arithmetic ABS.fmt and NEG.fmt emulation 
wired to the state of the FCSR.ABS2008 bit.  In the non-arithmetic mode 
the sign bit is altered according to the operation requested regardless 
of the datum encoded in the input operand, no other bits are changed, 
the resulting bit pattern is written to the output operand and no 
exception is ever signalled.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
linux-mips-emu-abs2008.diff
Index: linux-sfr-test/arch/mips/math-emu/dp_simple.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/dp_simple.c	2015-11-10 17:45:25.145419000 +0000
+++ linux-sfr-test/arch/mips/math-emu/dp_simple.c	2015-11-11 02:19:59.120054000 +0000
@@ -23,27 +23,39 @@
 
 union ieee754dp ieee754dp_neg(union ieee754dp x)
 {
-	unsigned int oldrm;
 	union ieee754dp y;
 
-	oldrm = ieee754_csr.rm;
-	ieee754_csr.rm = FPU_CSR_RD;
-	y = ieee754dp_sub(ieee754dp_zero(0), x);
-	ieee754_csr.rm = oldrm;
+	if (ieee754_csr.abs2008) {
+		y = x;
+		DPSIGN(y) = !DPSIGN(x);
+	} else {
+		unsigned int oldrm;
+
+		oldrm = ieee754_csr.rm;
+		ieee754_csr.rm = FPU_CSR_RD;
+		y = ieee754dp_sub(ieee754dp_zero(0), x);
+		ieee754_csr.rm = oldrm;
+	}
 	return y;
 }
 
 union ieee754dp ieee754dp_abs(union ieee754dp x)
 {
-	unsigned int oldrm;
 	union ieee754dp y;
 
-	oldrm = ieee754_csr.rm;
-	ieee754_csr.rm = FPU_CSR_RD;
-	if (DPSIGN(x))
-		y = ieee754dp_sub(ieee754dp_zero(0), x);
-	else
-		y = ieee754dp_add(ieee754dp_zero(0), x);
-	ieee754_csr.rm = oldrm;
+	if (ieee754_csr.abs2008) {
+		y = x;
+		DPSIGN(y) = 0;
+	} else {
+		unsigned int oldrm;
+
+		oldrm = ieee754_csr.rm;
+		ieee754_csr.rm = FPU_CSR_RD;
+		if (DPSIGN(x))
+			y = ieee754dp_sub(ieee754dp_zero(0), x);
+		else
+			y = ieee754dp_add(ieee754dp_zero(0), x);
+		ieee754_csr.rm = oldrm;
+	}
 	return y;
 }
Index: linux-sfr-test/arch/mips/math-emu/sp_simple.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/sp_simple.c	2015-11-10 17:45:25.147428000 +0000
+++ linux-sfr-test/arch/mips/math-emu/sp_simple.c	2015-11-11 02:19:59.165062000 +0000
@@ -23,27 +23,39 @@
 
 union ieee754sp ieee754sp_neg(union ieee754sp x)
 {
-	unsigned int oldrm;
 	union ieee754sp y;
 
-	oldrm = ieee754_csr.rm;
-	ieee754_csr.rm = FPU_CSR_RD;
-	y = ieee754sp_sub(ieee754sp_zero(0), x);
-	ieee754_csr.rm = oldrm;
+	if (ieee754_csr.abs2008) {
+		y = x;
+		SPSIGN(y) = !SPSIGN(x);
+	} else {
+		unsigned int oldrm;
+
+		oldrm = ieee754_csr.rm;
+		ieee754_csr.rm = FPU_CSR_RD;
+		y = ieee754sp_sub(ieee754sp_zero(0), x);
+		ieee754_csr.rm = oldrm;
+	}
 	return y;
 }
 
 union ieee754sp ieee754sp_abs(union ieee754sp x)
 {
-	unsigned int oldrm;
 	union ieee754sp y;
 
-	oldrm = ieee754_csr.rm;
-	ieee754_csr.rm = FPU_CSR_RD;
-	if (SPSIGN(x))
-		y = ieee754sp_sub(ieee754sp_zero(0), x);
-	else
-		y = ieee754sp_add(ieee754sp_zero(0), x);
-	ieee754_csr.rm = oldrm;
+	if (ieee754_csr.abs2008) {
+		y = x;
+		SPSIGN(y) = 0;
+	} else {
+		unsigned int oldrm;
+
+		oldrm = ieee754_csr.rm;
+		ieee754_csr.rm = FPU_CSR_RD;
+		if (SPSIGN(x))
+			y = ieee754sp_sub(ieee754sp_zero(0), x);
+		else
+			y = ieee754sp_add(ieee754sp_zero(0), x);
+		ieee754_csr.rm = oldrm;
+	}
 	return y;
 }

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 3/8] MIPS: math-emu: Add IEEE Std 754-2008 ABS.fmt and NEG.fmt emulation
@ 2015-11-13  0:47   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:47 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Implement IEEE Std 754-2008 non-arithmetic ABS.fmt and NEG.fmt emulation 
wired to the state of the FCSR.ABS2008 bit.  In the non-arithmetic mode 
the sign bit is altered according to the operation requested regardless 
of the datum encoded in the input operand, no other bits are changed, 
the resulting bit pattern is written to the output operand and no 
exception is ever signalled.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
linux-mips-emu-abs2008.diff
Index: linux-sfr-test/arch/mips/math-emu/dp_simple.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/dp_simple.c	2015-11-10 17:45:25.145419000 +0000
+++ linux-sfr-test/arch/mips/math-emu/dp_simple.c	2015-11-11 02:19:59.120054000 +0000
@@ -23,27 +23,39 @@
 
 union ieee754dp ieee754dp_neg(union ieee754dp x)
 {
-	unsigned int oldrm;
 	union ieee754dp y;
 
-	oldrm = ieee754_csr.rm;
-	ieee754_csr.rm = FPU_CSR_RD;
-	y = ieee754dp_sub(ieee754dp_zero(0), x);
-	ieee754_csr.rm = oldrm;
+	if (ieee754_csr.abs2008) {
+		y = x;
+		DPSIGN(y) = !DPSIGN(x);
+	} else {
+		unsigned int oldrm;
+
+		oldrm = ieee754_csr.rm;
+		ieee754_csr.rm = FPU_CSR_RD;
+		y = ieee754dp_sub(ieee754dp_zero(0), x);
+		ieee754_csr.rm = oldrm;
+	}
 	return y;
 }
 
 union ieee754dp ieee754dp_abs(union ieee754dp x)
 {
-	unsigned int oldrm;
 	union ieee754dp y;
 
-	oldrm = ieee754_csr.rm;
-	ieee754_csr.rm = FPU_CSR_RD;
-	if (DPSIGN(x))
-		y = ieee754dp_sub(ieee754dp_zero(0), x);
-	else
-		y = ieee754dp_add(ieee754dp_zero(0), x);
-	ieee754_csr.rm = oldrm;
+	if (ieee754_csr.abs2008) {
+		y = x;
+		DPSIGN(y) = 0;
+	} else {
+		unsigned int oldrm;
+
+		oldrm = ieee754_csr.rm;
+		ieee754_csr.rm = FPU_CSR_RD;
+		if (DPSIGN(x))
+			y = ieee754dp_sub(ieee754dp_zero(0), x);
+		else
+			y = ieee754dp_add(ieee754dp_zero(0), x);
+		ieee754_csr.rm = oldrm;
+	}
 	return y;
 }
Index: linux-sfr-test/arch/mips/math-emu/sp_simple.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/sp_simple.c	2015-11-10 17:45:25.147428000 +0000
+++ linux-sfr-test/arch/mips/math-emu/sp_simple.c	2015-11-11 02:19:59.165062000 +0000
@@ -23,27 +23,39 @@
 
 union ieee754sp ieee754sp_neg(union ieee754sp x)
 {
-	unsigned int oldrm;
 	union ieee754sp y;
 
-	oldrm = ieee754_csr.rm;
-	ieee754_csr.rm = FPU_CSR_RD;
-	y = ieee754sp_sub(ieee754sp_zero(0), x);
-	ieee754_csr.rm = oldrm;
+	if (ieee754_csr.abs2008) {
+		y = x;
+		SPSIGN(y) = !SPSIGN(x);
+	} else {
+		unsigned int oldrm;
+
+		oldrm = ieee754_csr.rm;
+		ieee754_csr.rm = FPU_CSR_RD;
+		y = ieee754sp_sub(ieee754sp_zero(0), x);
+		ieee754_csr.rm = oldrm;
+	}
 	return y;
 }
 
 union ieee754sp ieee754sp_abs(union ieee754sp x)
 {
-	unsigned int oldrm;
 	union ieee754sp y;
 
-	oldrm = ieee754_csr.rm;
-	ieee754_csr.rm = FPU_CSR_RD;
-	if (SPSIGN(x))
-		y = ieee754sp_sub(ieee754sp_zero(0), x);
-	else
-		y = ieee754sp_add(ieee754sp_zero(0), x);
-	ieee754_csr.rm = oldrm;
+	if (ieee754_csr.abs2008) {
+		y = x;
+		SPSIGN(y) = 0;
+	} else {
+		unsigned int oldrm;
+
+		oldrm = ieee754_csr.rm;
+		ieee754_csr.rm = FPU_CSR_RD;
+		if (SPSIGN(x))
+			y = ieee754sp_sub(ieee754sp_zero(0), x);
+		else
+			y = ieee754sp_add(ieee754sp_zero(0), x);
+		ieee754_csr.rm = oldrm;
+	}
 	return y;
 }

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 4/8] MIPS: math-emu: Add IEEE Std 754-2008 NaN encoding emulation
@ 2015-11-13  0:47   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:47 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Implement IEEE Std 754-2008 NaN encoding wired to the state of the 
FCSR.NAN2008 bit.  Make the interpretation of the quiet bit in NaN data 
as follows:

* in the legacy mode originally defined by the MIPS architecture the 
  value of 1 denotes an sNaN whereas the value of 0 denotes a qNaN,

* in the 2008 mode introduced with revision 5 of the MIPS architecture 
  the value of 0 denotes an sNaN whereas the value of 1 denotes a qNaN, 
  following the definition of the preferred NaN encoding introduced with 
  IEEE Std 754-2008.

In the 2008 mode, following the requirement of the said standard, quiet 
an sNaN where needed by setting the quiet bit to 1 and leaving all the 
NaN payload bits unchanged.

Update format conversion operations according to the rules set by IEEE 
Std 754-2008 and the MIPS architecture.  Specifically:

* propagate NaN payload bits through conversions between floating-point 
  formats such that as much information as possible is preserved and 
  specifically a conversion from a narrower format to a wider format and 
  then back to the original format does not change a qNaN payload in any 
  way,

* conversions from a floating-point to an integer format where the 
  source is a NaN, infinity or a value that would convert to an integer 
  outside the range of the result format produce, under the default 
  exception handling, the respective values defined by the MIPS 
  architecture.

In full FPU emulation set the FIR.HAS2008 bit to 1, however do not make 
any further FCSR bits writable.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
linux-mips-emu-nan2008.diff
Index: linux-sfr-test/arch/mips/kernel/cpu-probe.c
===================================================================
--- linux-sfr-test.orig/arch/mips/kernel/cpu-probe.c	2015-09-04 21:34:10.000000000 +0100
+++ linux-sfr-test/arch/mips/kernel/cpu-probe.c	2015-09-04 21:35:56.582838000 +0100
@@ -113,6 +113,8 @@ static void cpu_set_nofpu_id(struct cpui
 	if (c->isa_level & (MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
 			    MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6))
 		value |= MIPS_FPIR_F64 | MIPS_FPIR_L | MIPS_FPIR_W;
+	if (c->options & MIPS_CPU_NAN_2008)
+		value |= MIPS_FPIR_HAS2008;
 	c->fpu_id = value;
 }
 
Index: linux-sfr-test/arch/mips/math-emu/dp_tint.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/dp_tint.c	2015-04-08 16:56:50.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/dp_tint.c	2015-09-04 21:35:56.587767000 +0100
@@ -38,10 +38,13 @@ int ieee754dp_tint(union ieee754dp x)
 	switch (xc) {
 	case IEEE754_CLASS_SNAN:
 	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_INF:
 		ieee754_setcx(IEEE754_INVALID_OPERATION);
 		return ieee754si_indef();
 
+	case IEEE754_CLASS_INF:
+		ieee754_setcx(IEEE754_INVALID_OPERATION);
+		return ieee754si_overflow(xs);
+
 	case IEEE754_CLASS_ZERO:
 		return 0;
 
@@ -53,7 +56,7 @@ int ieee754dp_tint(union ieee754dp x)
 		/* Set invalid. We will only use overflow for floating
 		   point overflow */
 		ieee754_setcx(IEEE754_INVALID_OPERATION);
-		return ieee754si_indef();
+		return ieee754si_overflow(xs);
 	}
 	/* oh gawd */
 	if (xe > DP_FBITS) {
@@ -93,7 +96,7 @@ int ieee754dp_tint(union ieee754dp x)
 		if ((xm >> 31) != 0 && (xs == 0 || xm != 0x80000000)) {
 			/* This can happen after rounding */
 			ieee754_setcx(IEEE754_INVALID_OPERATION);
-			return ieee754si_indef();
+			return ieee754si_overflow(xs);
 		}
 		if (round || sticky)
 			ieee754_setcx(IEEE754_INEXACT);
Index: linux-sfr-test/arch/mips/math-emu/dp_tlong.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/dp_tlong.c	2015-04-08 16:56:50.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/dp_tlong.c	2015-09-04 21:35:56.589811000 +0100
@@ -38,10 +38,13 @@ s64 ieee754dp_tlong(union ieee754dp x)
 	switch (xc) {
 	case IEEE754_CLASS_SNAN:
 	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_INF:
 		ieee754_setcx(IEEE754_INVALID_OPERATION);
 		return ieee754di_indef();
 
+	case IEEE754_CLASS_INF:
+		ieee754_setcx(IEEE754_INVALID_OPERATION);
+		return ieee754di_overflow(xs);
+
 	case IEEE754_CLASS_ZERO:
 		return 0;
 
@@ -56,7 +59,7 @@ s64 ieee754dp_tlong(union ieee754dp x)
 		/* Set invalid. We will only use overflow for floating
 		   point overflow */
 		ieee754_setcx(IEEE754_INVALID_OPERATION);
-		return ieee754di_indef();
+		return ieee754di_overflow(xs);
 	}
 	/* oh gawd */
 	if (xe > DP_FBITS) {
@@ -97,7 +100,7 @@ s64 ieee754dp_tlong(union ieee754dp x)
 		if ((xm >> 63) != 0) {
 			/* This can happen after rounding */
 			ieee754_setcx(IEEE754_INVALID_OPERATION);
-			return ieee754di_indef();
+			return ieee754di_overflow(xs);
 		}
 		if (round || sticky)
 			ieee754_setcx(IEEE754_INEXACT);
Index: linux-sfr-test/arch/mips/math-emu/ieee754.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/ieee754.c	2015-04-08 16:56:50.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/ieee754.c	2015-09-04 21:35:56.592775000 +0100
@@ -59,7 +59,8 @@ const union ieee754dp __ieee754dp_spcval
 	DPCNST(1, 3,           0x4000000000000ULL),	/* - 10.0   */
 	DPCNST(0, DP_EMAX + 1, 0x0000000000000ULL),	/* + infinity */
 	DPCNST(1, DP_EMAX + 1, 0x0000000000000ULL),	/* - infinity */
-	DPCNST(0, DP_EMAX + 1, 0x7FFFFFFFFFFFFULL),	/* + indef quiet Nan */
+	DPCNST(0, DP_EMAX + 1, 0x7FFFFFFFFFFFFULL),	/* + ind legacy qNaN */
+	DPCNST(0, DP_EMAX + 1, 0x8000000000000ULL),	/* + indef 2008 qNaN */
 	DPCNST(0, DP_EMAX,     0xFFFFFFFFFFFFFULL),	/* + max */
 	DPCNST(1, DP_EMAX,     0xFFFFFFFFFFFFFULL),	/* - max */
 	DPCNST(0, DP_EMIN,     0x0000000000000ULL),	/* + min normal */
@@ -82,7 +83,8 @@ const union ieee754sp __ieee754sp_spcval
 	SPCNST(1, 3,	       0x200000),	/* - 10.0   */
 	SPCNST(0, SP_EMAX + 1, 0x000000),	/* + infinity */
 	SPCNST(1, SP_EMAX + 1, 0x000000),	/* - infinity */
-	SPCNST(0, SP_EMAX + 1, 0x3FFFFF),	/* + indef quiet Nan  */
+	SPCNST(0, SP_EMAX + 1, 0x3FFFFF),	/* + indef legacy quiet NaN */
+	SPCNST(0, SP_EMAX + 1, 0x400000),	/* + indef 2008 quiet NaN */
 	SPCNST(0, SP_EMAX,     0x7FFFFF),	/* + max normal */
 	SPCNST(1, SP_EMAX,     0x7FFFFF),	/* - max normal */
 	SPCNST(0, SP_EMIN,     0x000000),	/* + min normal */
Index: linux-sfr-test/arch/mips/math-emu/ieee754.h
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/ieee754.h	2015-09-04 19:19:07.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/ieee754.h	2015-09-04 21:35:56.594791000 +0100
@@ -221,15 +221,16 @@ union ieee754dp ieee754dp_dump(char *s, 
 #define IEEE754_SPCVAL_NTEN		5	/* -10.0 */
 #define IEEE754_SPCVAL_PINFINITY	6	/* +inf */
 #define IEEE754_SPCVAL_NINFINITY	7	/* -inf */
-#define IEEE754_SPCVAL_INDEF		8	/* quiet NaN */
-#define IEEE754_SPCVAL_PMAX		9	/* +max norm */
-#define IEEE754_SPCVAL_NMAX		10	/* -max norm */
-#define IEEE754_SPCVAL_PMIN		11	/* +min norm */
-#define IEEE754_SPCVAL_NMIN		12	/* -min norm */
-#define IEEE754_SPCVAL_PMIND		13	/* +min denorm */
-#define IEEE754_SPCVAL_NMIND		14	/* -min denorm */
-#define IEEE754_SPCVAL_P1E31		15	/* + 1.0e31 */
-#define IEEE754_SPCVAL_P1E63		16	/* + 1.0e63 */
+#define IEEE754_SPCVAL_INDEF_LEG	8	/* legacy quiet NaN */
+#define IEEE754_SPCVAL_INDEF_2008	9	/* IEEE 754-2008 quiet NaN */
+#define IEEE754_SPCVAL_PMAX		10	/* +max norm */
+#define IEEE754_SPCVAL_NMAX		11	/* -max norm */
+#define IEEE754_SPCVAL_PMIN		12	/* +min norm */
+#define IEEE754_SPCVAL_NMIN		13	/* -min norm */
+#define IEEE754_SPCVAL_PMIND		14	/* +min denorm */
+#define IEEE754_SPCVAL_NMIND		15	/* -min denorm */
+#define IEEE754_SPCVAL_P1E31		16	/* + 1.0e31 */
+#define IEEE754_SPCVAL_P1E63		17	/* + 1.0e63 */
 
 extern const union ieee754dp __ieee754dp_spcvals[];
 extern const union ieee754sp __ieee754sp_spcvals[];
@@ -243,7 +244,8 @@ extern const union ieee754sp __ieee754sp
 #define ieee754dp_zero(sn)	(ieee754dp_spcvals[IEEE754_SPCVAL_PZERO+(sn)])
 #define ieee754dp_one(sn)	(ieee754dp_spcvals[IEEE754_SPCVAL_PONE+(sn)])
 #define ieee754dp_ten(sn)	(ieee754dp_spcvals[IEEE754_SPCVAL_PTEN+(sn)])
-#define ieee754dp_indef()	(ieee754dp_spcvals[IEEE754_SPCVAL_INDEF])
+#define ieee754dp_indef()	(ieee754dp_spcvals[IEEE754_SPCVAL_INDEF_LEG + \
+						   ieee754_csr.nan2008])
 #define ieee754dp_max(sn)	(ieee754dp_spcvals[IEEE754_SPCVAL_PMAX+(sn)])
 #define ieee754dp_min(sn)	(ieee754dp_spcvals[IEEE754_SPCVAL_PMIN+(sn)])
 #define ieee754dp_mind(sn)	(ieee754dp_spcvals[IEEE754_SPCVAL_PMIND+(sn)])
@@ -254,7 +256,8 @@ extern const union ieee754sp __ieee754sp
 #define ieee754sp_zero(sn)	(ieee754sp_spcvals[IEEE754_SPCVAL_PZERO+(sn)])
 #define ieee754sp_one(sn)	(ieee754sp_spcvals[IEEE754_SPCVAL_PONE+(sn)])
 #define ieee754sp_ten(sn)	(ieee754sp_spcvals[IEEE754_SPCVAL_PTEN+(sn)])
-#define ieee754sp_indef()	(ieee754sp_spcvals[IEEE754_SPCVAL_INDEF])
+#define ieee754sp_indef()	(ieee754sp_spcvals[IEEE754_SPCVAL_INDEF_LEG + \
+						   ieee754_csr.nan2008])
 #define ieee754sp_max(sn)	(ieee754sp_spcvals[IEEE754_SPCVAL_PMAX+(sn)])
 #define ieee754sp_min(sn)	(ieee754sp_spcvals[IEEE754_SPCVAL_PMIN+(sn)])
 #define ieee754sp_mind(sn)	(ieee754sp_spcvals[IEEE754_SPCVAL_PMIND+(sn)])
@@ -266,12 +269,25 @@ extern const union ieee754sp __ieee754sp
  */
 static inline int ieee754si_indef(void)
 {
-	return INT_MAX;
+	return ieee754_csr.nan2008 ? 0 : INT_MAX;
 }
 
 static inline s64 ieee754di_indef(void)
 {
-	return S64_MAX;
+	return ieee754_csr.nan2008 ? 0 : S64_MAX;
+}
+
+/*
+ * Overflow integer value
+ */
+static inline int ieee754si_overflow(int xs)
+{
+	return ieee754_csr.nan2008 && xs ? INT_MIN : INT_MAX;
+}
+
+static inline s64 ieee754di_overflow(int xs)
+{
+	return ieee754_csr.nan2008 && xs ? S64_MIN : S64_MAX;
 }
 
 /* result types for xctx.rt */
Index: linux-sfr-test/arch/mips/math-emu/ieee754dp.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/ieee754dp.c	2015-04-08 16:56:50.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/ieee754dp.c	2015-09-04 21:35:56.597771000 +0100
@@ -37,8 +37,11 @@ static inline int ieee754dp_isnan(union 
 
 static inline int ieee754dp_issnan(union ieee754dp x)
 {
+	int qbit;
+
 	assert(ieee754dp_isnan(x));
-	return (DPMANT(x) & DP_MBIT(DP_FBITS - 1)) == DP_MBIT(DP_FBITS - 1);
+	qbit = (DPMANT(x) & DP_MBIT(DP_FBITS - 1)) == DP_MBIT(DP_FBITS - 1);
+	return ieee754_csr.nan2008 ^ qbit;
 }
 
 
@@ -51,7 +54,12 @@ union ieee754dp __cold ieee754dp_nanxcpt
 	assert(ieee754dp_issnan(r));
 
 	ieee754_setcx(IEEE754_INVALID_OPERATION);
-	return ieee754dp_indef();
+	if (ieee754_csr.nan2008)
+		DPMANT(r) |= DP_MBIT(DP_FBITS - 1);
+	else
+		r = ieee754dp_indef();
+
+	return r;
 }
 
 static u64 ieee754dp_get_rounding(int sn, u64 xm)
Index: linux-sfr-test/arch/mips/math-emu/ieee754int.h
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/ieee754int.h	2015-09-04 19:19:07.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/ieee754int.h	2015-09-04 21:35:56.599789000 +0100
@@ -63,10 +63,10 @@ static inline int ieee754_class_nan(int 
 	if (ve == SP_EMAX+1+SP_EBIAS) {					\
 		if (vm == 0)						\
 			vc = IEEE754_CLASS_INF;				\
-		else if (vm & SP_MBIT(SP_FBITS-1))			\
-			vc = IEEE754_CLASS_SNAN;			\
-		else							\
+		else if (ieee754_csr.nan2008 ^ !(vm & SP_MBIT(SP_FBITS - 1))) \
 			vc = IEEE754_CLASS_QNAN;			\
+		else							\
+			vc = IEEE754_CLASS_SNAN;			\
 	} else if (ve == SP_EMIN-1+SP_EBIAS) {				\
 		if (vm) {						\
 			ve = SP_EMIN;					\
@@ -97,10 +97,10 @@ static inline int ieee754_class_nan(int 
 	if (ve == DP_EMAX+1+DP_EBIAS) {					\
 		if (vm == 0)						\
 			vc = IEEE754_CLASS_INF;				\
-		else if (vm & DP_MBIT(DP_FBITS-1))			\
-			vc = IEEE754_CLASS_SNAN;			\
-		else							\
+		else if (ieee754_csr.nan2008 ^ !(vm & DP_MBIT(DP_FBITS - 1))) \
 			vc = IEEE754_CLASS_QNAN;			\
+		else							\
+			vc = IEEE754_CLASS_SNAN;			\
 	} else if (ve == DP_EMIN-1+DP_EBIAS) {				\
 		if (vm) {						\
 			ve = DP_EMIN;					\
Index: linux-sfr-test/arch/mips/math-emu/ieee754sp.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/ieee754sp.c	2015-04-08 16:56:50.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/ieee754sp.c	2015-09-04 21:35:56.602775000 +0100
@@ -37,8 +37,11 @@ static inline int ieee754sp_isnan(union 
 
 static inline int ieee754sp_issnan(union ieee754sp x)
 {
+	int qbit;
+
 	assert(ieee754sp_isnan(x));
-	return SPMANT(x) & SP_MBIT(SP_FBITS - 1);
+	qbit = (SPMANT(x) & SP_MBIT(SP_FBITS - 1)) == SP_MBIT(SP_FBITS - 1);
+	return ieee754_csr.nan2008 ^ qbit;
 }
 
 
@@ -51,7 +54,12 @@ union ieee754sp __cold ieee754sp_nanxcpt
 	assert(ieee754sp_issnan(r));
 
 	ieee754_setcx(IEEE754_INVALID_OPERATION);
-	return ieee754sp_indef();
+	if (ieee754_csr.nan2008)
+		SPMANT(r) |= SP_MBIT(SP_FBITS - 1);
+	else
+		r = ieee754sp_indef();
+
+	return r;
 }
 
 static unsigned ieee754sp_get_rounding(int sn, unsigned xm)
Index: linux-sfr-test/arch/mips/math-emu/sp_fdp.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/sp_fdp.c	2015-04-08 16:56:50.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/sp_fdp.c	2015-09-04 21:35:56.604814000 +0100
@@ -44,13 +44,16 @@ union ieee754sp ieee754sp_fdp(union ieee
 
 	switch (xc) {
 	case IEEE754_CLASS_SNAN:
-		return ieee754sp_nanxcpt(ieee754sp_nan_fdp(xs, xm));
-
+		x = ieee754dp_nanxcpt(x);
+		EXPLODEXDP;
+		/* Fall through.  */
 	case IEEE754_CLASS_QNAN:
 		y = ieee754sp_nan_fdp(xs, xm);
-		EXPLODEYSP;
-		if (!ieee754_class_nan(yc))
-			y = ieee754sp_indef();
+		if (!ieee754_csr.nan2008) {
+			EXPLODEYSP;
+			if (!ieee754_class_nan(yc))
+				y = ieee754sp_indef();
+		}
 		return y;
 
 	case IEEE754_CLASS_INF:
Index: linux-sfr-test/arch/mips/math-emu/sp_tint.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/sp_tint.c	2015-04-08 16:56:50.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/sp_tint.c	2015-09-04 21:35:56.607763000 +0100
@@ -38,10 +38,13 @@ int ieee754sp_tint(union ieee754sp x)
 	switch (xc) {
 	case IEEE754_CLASS_SNAN:
 	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_INF:
 		ieee754_setcx(IEEE754_INVALID_OPERATION);
 		return ieee754si_indef();
 
+	case IEEE754_CLASS_INF:
+		ieee754_setcx(IEEE754_INVALID_OPERATION);
+		return ieee754si_overflow(xs);
+
 	case IEEE754_CLASS_ZERO:
 		return 0;
 
@@ -56,7 +59,7 @@ int ieee754sp_tint(union ieee754sp x)
 		/* Set invalid. We will only use overflow for floating
 		   point overflow */
 		ieee754_setcx(IEEE754_INVALID_OPERATION);
-		return ieee754si_indef();
+		return ieee754si_overflow(xs);
 	}
 	/* oh gawd */
 	if (xe > SP_FBITS) {
@@ -97,7 +100,7 @@ int ieee754sp_tint(union ieee754sp x)
 		if ((xm >> 31) != 0) {
 			/* This can happen after rounding */
 			ieee754_setcx(IEEE754_INVALID_OPERATION);
-			return ieee754si_indef();
+			return ieee754si_overflow(xs);
 		}
 		if (round || sticky)
 			ieee754_setcx(IEEE754_INEXACT);
Index: linux-sfr-test/arch/mips/math-emu/sp_tlong.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/sp_tlong.c	2015-04-08 16:56:50.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/sp_tlong.c	2015-09-04 21:35:56.609788000 +0100
@@ -39,10 +39,13 @@ s64 ieee754sp_tlong(union ieee754sp x)
 	switch (xc) {
 	case IEEE754_CLASS_SNAN:
 	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_INF:
 		ieee754_setcx(IEEE754_INVALID_OPERATION);
 		return ieee754di_indef();
 
+	case IEEE754_CLASS_INF:
+		ieee754_setcx(IEEE754_INVALID_OPERATION);
+		return ieee754di_overflow(xs);
+
 	case IEEE754_CLASS_ZERO:
 		return 0;
 
@@ -57,7 +60,7 @@ s64 ieee754sp_tlong(union ieee754sp x)
 		/* Set invalid. We will only use overflow for floating
 		   point overflow */
 		ieee754_setcx(IEEE754_INVALID_OPERATION);
-		return ieee754di_indef();
+		return ieee754di_overflow(xs);
 	}
 	/* oh gawd */
 	if (xe > SP_FBITS) {
@@ -94,7 +97,7 @@ s64 ieee754sp_tlong(union ieee754sp x)
 		if ((xm >> 63) != 0) {
 			/* This can happen after rounding */
 			ieee754_setcx(IEEE754_INVALID_OPERATION);
-			return ieee754di_indef();
+			return ieee754di_overflow(xs);
 		}
 		if (round || sticky)
 			ieee754_setcx(IEEE754_INEXACT);

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 4/8] MIPS: math-emu: Add IEEE Std 754-2008 NaN encoding emulation
@ 2015-11-13  0:47   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:47 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Implement IEEE Std 754-2008 NaN encoding wired to the state of the 
FCSR.NAN2008 bit.  Make the interpretation of the quiet bit in NaN data 
as follows:

* in the legacy mode originally defined by the MIPS architecture the 
  value of 1 denotes an sNaN whereas the value of 0 denotes a qNaN,

* in the 2008 mode introduced with revision 5 of the MIPS architecture 
  the value of 0 denotes an sNaN whereas the value of 1 denotes a qNaN, 
  following the definition of the preferred NaN encoding introduced with 
  IEEE Std 754-2008.

In the 2008 mode, following the requirement of the said standard, quiet 
an sNaN where needed by setting the quiet bit to 1 and leaving all the 
NaN payload bits unchanged.

Update format conversion operations according to the rules set by IEEE 
Std 754-2008 and the MIPS architecture.  Specifically:

* propagate NaN payload bits through conversions between floating-point 
  formats such that as much information as possible is preserved and 
  specifically a conversion from a narrower format to a wider format and 
  then back to the original format does not change a qNaN payload in any 
  way,

* conversions from a floating-point to an integer format where the 
  source is a NaN, infinity or a value that would convert to an integer 
  outside the range of the result format produce, under the default 
  exception handling, the respective values defined by the MIPS 
  architecture.

In full FPU emulation set the FIR.HAS2008 bit to 1, however do not make 
any further FCSR bits writable.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
linux-mips-emu-nan2008.diff
Index: linux-sfr-test/arch/mips/kernel/cpu-probe.c
===================================================================
--- linux-sfr-test.orig/arch/mips/kernel/cpu-probe.c	2015-09-04 21:34:10.000000000 +0100
+++ linux-sfr-test/arch/mips/kernel/cpu-probe.c	2015-09-04 21:35:56.582838000 +0100
@@ -113,6 +113,8 @@ static void cpu_set_nofpu_id(struct cpui
 	if (c->isa_level & (MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
 			    MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6))
 		value |= MIPS_FPIR_F64 | MIPS_FPIR_L | MIPS_FPIR_W;
+	if (c->options & MIPS_CPU_NAN_2008)
+		value |= MIPS_FPIR_HAS2008;
 	c->fpu_id = value;
 }
 
Index: linux-sfr-test/arch/mips/math-emu/dp_tint.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/dp_tint.c	2015-04-08 16:56:50.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/dp_tint.c	2015-09-04 21:35:56.587767000 +0100
@@ -38,10 +38,13 @@ int ieee754dp_tint(union ieee754dp x)
 	switch (xc) {
 	case IEEE754_CLASS_SNAN:
 	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_INF:
 		ieee754_setcx(IEEE754_INVALID_OPERATION);
 		return ieee754si_indef();
 
+	case IEEE754_CLASS_INF:
+		ieee754_setcx(IEEE754_INVALID_OPERATION);
+		return ieee754si_overflow(xs);
+
 	case IEEE754_CLASS_ZERO:
 		return 0;
 
@@ -53,7 +56,7 @@ int ieee754dp_tint(union ieee754dp x)
 		/* Set invalid. We will only use overflow for floating
 		   point overflow */
 		ieee754_setcx(IEEE754_INVALID_OPERATION);
-		return ieee754si_indef();
+		return ieee754si_overflow(xs);
 	}
 	/* oh gawd */
 	if (xe > DP_FBITS) {
@@ -93,7 +96,7 @@ int ieee754dp_tint(union ieee754dp x)
 		if ((xm >> 31) != 0 && (xs == 0 || xm != 0x80000000)) {
 			/* This can happen after rounding */
 			ieee754_setcx(IEEE754_INVALID_OPERATION);
-			return ieee754si_indef();
+			return ieee754si_overflow(xs);
 		}
 		if (round || sticky)
 			ieee754_setcx(IEEE754_INEXACT);
Index: linux-sfr-test/arch/mips/math-emu/dp_tlong.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/dp_tlong.c	2015-04-08 16:56:50.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/dp_tlong.c	2015-09-04 21:35:56.589811000 +0100
@@ -38,10 +38,13 @@ s64 ieee754dp_tlong(union ieee754dp x)
 	switch (xc) {
 	case IEEE754_CLASS_SNAN:
 	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_INF:
 		ieee754_setcx(IEEE754_INVALID_OPERATION);
 		return ieee754di_indef();
 
+	case IEEE754_CLASS_INF:
+		ieee754_setcx(IEEE754_INVALID_OPERATION);
+		return ieee754di_overflow(xs);
+
 	case IEEE754_CLASS_ZERO:
 		return 0;
 
@@ -56,7 +59,7 @@ s64 ieee754dp_tlong(union ieee754dp x)
 		/* Set invalid. We will only use overflow for floating
 		   point overflow */
 		ieee754_setcx(IEEE754_INVALID_OPERATION);
-		return ieee754di_indef();
+		return ieee754di_overflow(xs);
 	}
 	/* oh gawd */
 	if (xe > DP_FBITS) {
@@ -97,7 +100,7 @@ s64 ieee754dp_tlong(union ieee754dp x)
 		if ((xm >> 63) != 0) {
 			/* This can happen after rounding */
 			ieee754_setcx(IEEE754_INVALID_OPERATION);
-			return ieee754di_indef();
+			return ieee754di_overflow(xs);
 		}
 		if (round || sticky)
 			ieee754_setcx(IEEE754_INEXACT);
Index: linux-sfr-test/arch/mips/math-emu/ieee754.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/ieee754.c	2015-04-08 16:56:50.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/ieee754.c	2015-09-04 21:35:56.592775000 +0100
@@ -59,7 +59,8 @@ const union ieee754dp __ieee754dp_spcval
 	DPCNST(1, 3,           0x4000000000000ULL),	/* - 10.0   */
 	DPCNST(0, DP_EMAX + 1, 0x0000000000000ULL),	/* + infinity */
 	DPCNST(1, DP_EMAX + 1, 0x0000000000000ULL),	/* - infinity */
-	DPCNST(0, DP_EMAX + 1, 0x7FFFFFFFFFFFFULL),	/* + indef quiet Nan */
+	DPCNST(0, DP_EMAX + 1, 0x7FFFFFFFFFFFFULL),	/* + ind legacy qNaN */
+	DPCNST(0, DP_EMAX + 1, 0x8000000000000ULL),	/* + indef 2008 qNaN */
 	DPCNST(0, DP_EMAX,     0xFFFFFFFFFFFFFULL),	/* + max */
 	DPCNST(1, DP_EMAX,     0xFFFFFFFFFFFFFULL),	/* - max */
 	DPCNST(0, DP_EMIN,     0x0000000000000ULL),	/* + min normal */
@@ -82,7 +83,8 @@ const union ieee754sp __ieee754sp_spcval
 	SPCNST(1, 3,	       0x200000),	/* - 10.0   */
 	SPCNST(0, SP_EMAX + 1, 0x000000),	/* + infinity */
 	SPCNST(1, SP_EMAX + 1, 0x000000),	/* - infinity */
-	SPCNST(0, SP_EMAX + 1, 0x3FFFFF),	/* + indef quiet Nan  */
+	SPCNST(0, SP_EMAX + 1, 0x3FFFFF),	/* + indef legacy quiet NaN */
+	SPCNST(0, SP_EMAX + 1, 0x400000),	/* + indef 2008 quiet NaN */
 	SPCNST(0, SP_EMAX,     0x7FFFFF),	/* + max normal */
 	SPCNST(1, SP_EMAX,     0x7FFFFF),	/* - max normal */
 	SPCNST(0, SP_EMIN,     0x000000),	/* + min normal */
Index: linux-sfr-test/arch/mips/math-emu/ieee754.h
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/ieee754.h	2015-09-04 19:19:07.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/ieee754.h	2015-09-04 21:35:56.594791000 +0100
@@ -221,15 +221,16 @@ union ieee754dp ieee754dp_dump(char *s, 
 #define IEEE754_SPCVAL_NTEN		5	/* -10.0 */
 #define IEEE754_SPCVAL_PINFINITY	6	/* +inf */
 #define IEEE754_SPCVAL_NINFINITY	7	/* -inf */
-#define IEEE754_SPCVAL_INDEF		8	/* quiet NaN */
-#define IEEE754_SPCVAL_PMAX		9	/* +max norm */
-#define IEEE754_SPCVAL_NMAX		10	/* -max norm */
-#define IEEE754_SPCVAL_PMIN		11	/* +min norm */
-#define IEEE754_SPCVAL_NMIN		12	/* -min norm */
-#define IEEE754_SPCVAL_PMIND		13	/* +min denorm */
-#define IEEE754_SPCVAL_NMIND		14	/* -min denorm */
-#define IEEE754_SPCVAL_P1E31		15	/* + 1.0e31 */
-#define IEEE754_SPCVAL_P1E63		16	/* + 1.0e63 */
+#define IEEE754_SPCVAL_INDEF_LEG	8	/* legacy quiet NaN */
+#define IEEE754_SPCVAL_INDEF_2008	9	/* IEEE 754-2008 quiet NaN */
+#define IEEE754_SPCVAL_PMAX		10	/* +max norm */
+#define IEEE754_SPCVAL_NMAX		11	/* -max norm */
+#define IEEE754_SPCVAL_PMIN		12	/* +min norm */
+#define IEEE754_SPCVAL_NMIN		13	/* -min norm */
+#define IEEE754_SPCVAL_PMIND		14	/* +min denorm */
+#define IEEE754_SPCVAL_NMIND		15	/* -min denorm */
+#define IEEE754_SPCVAL_P1E31		16	/* + 1.0e31 */
+#define IEEE754_SPCVAL_P1E63		17	/* + 1.0e63 */
 
 extern const union ieee754dp __ieee754dp_spcvals[];
 extern const union ieee754sp __ieee754sp_spcvals[];
@@ -243,7 +244,8 @@ extern const union ieee754sp __ieee754sp
 #define ieee754dp_zero(sn)	(ieee754dp_spcvals[IEEE754_SPCVAL_PZERO+(sn)])
 #define ieee754dp_one(sn)	(ieee754dp_spcvals[IEEE754_SPCVAL_PONE+(sn)])
 #define ieee754dp_ten(sn)	(ieee754dp_spcvals[IEEE754_SPCVAL_PTEN+(sn)])
-#define ieee754dp_indef()	(ieee754dp_spcvals[IEEE754_SPCVAL_INDEF])
+#define ieee754dp_indef()	(ieee754dp_spcvals[IEEE754_SPCVAL_INDEF_LEG + \
+						   ieee754_csr.nan2008])
 #define ieee754dp_max(sn)	(ieee754dp_spcvals[IEEE754_SPCVAL_PMAX+(sn)])
 #define ieee754dp_min(sn)	(ieee754dp_spcvals[IEEE754_SPCVAL_PMIN+(sn)])
 #define ieee754dp_mind(sn)	(ieee754dp_spcvals[IEEE754_SPCVAL_PMIND+(sn)])
@@ -254,7 +256,8 @@ extern const union ieee754sp __ieee754sp
 #define ieee754sp_zero(sn)	(ieee754sp_spcvals[IEEE754_SPCVAL_PZERO+(sn)])
 #define ieee754sp_one(sn)	(ieee754sp_spcvals[IEEE754_SPCVAL_PONE+(sn)])
 #define ieee754sp_ten(sn)	(ieee754sp_spcvals[IEEE754_SPCVAL_PTEN+(sn)])
-#define ieee754sp_indef()	(ieee754sp_spcvals[IEEE754_SPCVAL_INDEF])
+#define ieee754sp_indef()	(ieee754sp_spcvals[IEEE754_SPCVAL_INDEF_LEG + \
+						   ieee754_csr.nan2008])
 #define ieee754sp_max(sn)	(ieee754sp_spcvals[IEEE754_SPCVAL_PMAX+(sn)])
 #define ieee754sp_min(sn)	(ieee754sp_spcvals[IEEE754_SPCVAL_PMIN+(sn)])
 #define ieee754sp_mind(sn)	(ieee754sp_spcvals[IEEE754_SPCVAL_PMIND+(sn)])
@@ -266,12 +269,25 @@ extern const union ieee754sp __ieee754sp
  */
 static inline int ieee754si_indef(void)
 {
-	return INT_MAX;
+	return ieee754_csr.nan2008 ? 0 : INT_MAX;
 }
 
 static inline s64 ieee754di_indef(void)
 {
-	return S64_MAX;
+	return ieee754_csr.nan2008 ? 0 : S64_MAX;
+}
+
+/*
+ * Overflow integer value
+ */
+static inline int ieee754si_overflow(int xs)
+{
+	return ieee754_csr.nan2008 && xs ? INT_MIN : INT_MAX;
+}
+
+static inline s64 ieee754di_overflow(int xs)
+{
+	return ieee754_csr.nan2008 && xs ? S64_MIN : S64_MAX;
 }
 
 /* result types for xctx.rt */
Index: linux-sfr-test/arch/mips/math-emu/ieee754dp.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/ieee754dp.c	2015-04-08 16:56:50.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/ieee754dp.c	2015-09-04 21:35:56.597771000 +0100
@@ -37,8 +37,11 @@ static inline int ieee754dp_isnan(union 
 
 static inline int ieee754dp_issnan(union ieee754dp x)
 {
+	int qbit;
+
 	assert(ieee754dp_isnan(x));
-	return (DPMANT(x) & DP_MBIT(DP_FBITS - 1)) == DP_MBIT(DP_FBITS - 1);
+	qbit = (DPMANT(x) & DP_MBIT(DP_FBITS - 1)) == DP_MBIT(DP_FBITS - 1);
+	return ieee754_csr.nan2008 ^ qbit;
 }
 
 
@@ -51,7 +54,12 @@ union ieee754dp __cold ieee754dp_nanxcpt
 	assert(ieee754dp_issnan(r));
 
 	ieee754_setcx(IEEE754_INVALID_OPERATION);
-	return ieee754dp_indef();
+	if (ieee754_csr.nan2008)
+		DPMANT(r) |= DP_MBIT(DP_FBITS - 1);
+	else
+		r = ieee754dp_indef();
+
+	return r;
 }
 
 static u64 ieee754dp_get_rounding(int sn, u64 xm)
Index: linux-sfr-test/arch/mips/math-emu/ieee754int.h
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/ieee754int.h	2015-09-04 19:19:07.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/ieee754int.h	2015-09-04 21:35:56.599789000 +0100
@@ -63,10 +63,10 @@ static inline int ieee754_class_nan(int 
 	if (ve == SP_EMAX+1+SP_EBIAS) {					\
 		if (vm == 0)						\
 			vc = IEEE754_CLASS_INF;				\
-		else if (vm & SP_MBIT(SP_FBITS-1))			\
-			vc = IEEE754_CLASS_SNAN;			\
-		else							\
+		else if (ieee754_csr.nan2008 ^ !(vm & SP_MBIT(SP_FBITS - 1))) \
 			vc = IEEE754_CLASS_QNAN;			\
+		else							\
+			vc = IEEE754_CLASS_SNAN;			\
 	} else if (ve == SP_EMIN-1+SP_EBIAS) {				\
 		if (vm) {						\
 			ve = SP_EMIN;					\
@@ -97,10 +97,10 @@ static inline int ieee754_class_nan(int 
 	if (ve == DP_EMAX+1+DP_EBIAS) {					\
 		if (vm == 0)						\
 			vc = IEEE754_CLASS_INF;				\
-		else if (vm & DP_MBIT(DP_FBITS-1))			\
-			vc = IEEE754_CLASS_SNAN;			\
-		else							\
+		else if (ieee754_csr.nan2008 ^ !(vm & DP_MBIT(DP_FBITS - 1))) \
 			vc = IEEE754_CLASS_QNAN;			\
+		else							\
+			vc = IEEE754_CLASS_SNAN;			\
 	} else if (ve == DP_EMIN-1+DP_EBIAS) {				\
 		if (vm) {						\
 			ve = DP_EMIN;					\
Index: linux-sfr-test/arch/mips/math-emu/ieee754sp.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/ieee754sp.c	2015-04-08 16:56:50.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/ieee754sp.c	2015-09-04 21:35:56.602775000 +0100
@@ -37,8 +37,11 @@ static inline int ieee754sp_isnan(union 
 
 static inline int ieee754sp_issnan(union ieee754sp x)
 {
+	int qbit;
+
 	assert(ieee754sp_isnan(x));
-	return SPMANT(x) & SP_MBIT(SP_FBITS - 1);
+	qbit = (SPMANT(x) & SP_MBIT(SP_FBITS - 1)) == SP_MBIT(SP_FBITS - 1);
+	return ieee754_csr.nan2008 ^ qbit;
 }
 
 
@@ -51,7 +54,12 @@ union ieee754sp __cold ieee754sp_nanxcpt
 	assert(ieee754sp_issnan(r));
 
 	ieee754_setcx(IEEE754_INVALID_OPERATION);
-	return ieee754sp_indef();
+	if (ieee754_csr.nan2008)
+		SPMANT(r) |= SP_MBIT(SP_FBITS - 1);
+	else
+		r = ieee754sp_indef();
+
+	return r;
 }
 
 static unsigned ieee754sp_get_rounding(int sn, unsigned xm)
Index: linux-sfr-test/arch/mips/math-emu/sp_fdp.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/sp_fdp.c	2015-04-08 16:56:50.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/sp_fdp.c	2015-09-04 21:35:56.604814000 +0100
@@ -44,13 +44,16 @@ union ieee754sp ieee754sp_fdp(union ieee
 
 	switch (xc) {
 	case IEEE754_CLASS_SNAN:
-		return ieee754sp_nanxcpt(ieee754sp_nan_fdp(xs, xm));
-
+		x = ieee754dp_nanxcpt(x);
+		EXPLODEXDP;
+		/* Fall through.  */
 	case IEEE754_CLASS_QNAN:
 		y = ieee754sp_nan_fdp(xs, xm);
-		EXPLODEYSP;
-		if (!ieee754_class_nan(yc))
-			y = ieee754sp_indef();
+		if (!ieee754_csr.nan2008) {
+			EXPLODEYSP;
+			if (!ieee754_class_nan(yc))
+				y = ieee754sp_indef();
+		}
 		return y;
 
 	case IEEE754_CLASS_INF:
Index: linux-sfr-test/arch/mips/math-emu/sp_tint.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/sp_tint.c	2015-04-08 16:56:50.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/sp_tint.c	2015-09-04 21:35:56.607763000 +0100
@@ -38,10 +38,13 @@ int ieee754sp_tint(union ieee754sp x)
 	switch (xc) {
 	case IEEE754_CLASS_SNAN:
 	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_INF:
 		ieee754_setcx(IEEE754_INVALID_OPERATION);
 		return ieee754si_indef();
 
+	case IEEE754_CLASS_INF:
+		ieee754_setcx(IEEE754_INVALID_OPERATION);
+		return ieee754si_overflow(xs);
+
 	case IEEE754_CLASS_ZERO:
 		return 0;
 
@@ -56,7 +59,7 @@ int ieee754sp_tint(union ieee754sp x)
 		/* Set invalid. We will only use overflow for floating
 		   point overflow */
 		ieee754_setcx(IEEE754_INVALID_OPERATION);
-		return ieee754si_indef();
+		return ieee754si_overflow(xs);
 	}
 	/* oh gawd */
 	if (xe > SP_FBITS) {
@@ -97,7 +100,7 @@ int ieee754sp_tint(union ieee754sp x)
 		if ((xm >> 31) != 0) {
 			/* This can happen after rounding */
 			ieee754_setcx(IEEE754_INVALID_OPERATION);
-			return ieee754si_indef();
+			return ieee754si_overflow(xs);
 		}
 		if (round || sticky)
 			ieee754_setcx(IEEE754_INEXACT);
Index: linux-sfr-test/arch/mips/math-emu/sp_tlong.c
===================================================================
--- linux-sfr-test.orig/arch/mips/math-emu/sp_tlong.c	2015-04-08 16:56:50.000000000 +0100
+++ linux-sfr-test/arch/mips/math-emu/sp_tlong.c	2015-09-04 21:35:56.609788000 +0100
@@ -39,10 +39,13 @@ s64 ieee754sp_tlong(union ieee754sp x)
 	switch (xc) {
 	case IEEE754_CLASS_SNAN:
 	case IEEE754_CLASS_QNAN:
-	case IEEE754_CLASS_INF:
 		ieee754_setcx(IEEE754_INVALID_OPERATION);
 		return ieee754di_indef();
 
+	case IEEE754_CLASS_INF:
+		ieee754_setcx(IEEE754_INVALID_OPERATION);
+		return ieee754di_overflow(xs);
+
 	case IEEE754_CLASS_ZERO:
 		return 0;
 
@@ -57,7 +60,7 @@ s64 ieee754sp_tlong(union ieee754sp x)
 		/* Set invalid. We will only use overflow for floating
 		   point overflow */
 		ieee754_setcx(IEEE754_INVALID_OPERATION);
-		return ieee754di_indef();
+		return ieee754di_overflow(xs);
 	}
 	/* oh gawd */
 	if (xe > SP_FBITS) {
@@ -94,7 +97,7 @@ s64 ieee754sp_tlong(union ieee754sp x)
 		if ((xm >> 63) != 0) {
 			/* This can happen after rounding */
 			ieee754_setcx(IEEE754_INVALID_OPERATION);
-			return ieee754di_indef();
+			return ieee754di_overflow(xs);
 		}
 		if (round || sticky)
 			ieee754_setcx(IEEE754_INEXACT);

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 5/8] ELF: Also pass any interpreter's file header to `arch_check_elf'
@ 2015-11-13  0:47   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:47 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Also pass any interpreter's file header to `arch_check_elf' so that any 
architecture handler can have a look at it if needed.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
linux-arch-check-elf-interp.diff
Index: linux-sfr-test/arch/mips/include/asm/elf.h
===================================================================
--- linux-sfr-test.orig/arch/mips/include/asm/elf.h	2015-11-10 18:06:16.547399000 +0000
+++ linux-sfr-test/arch/mips/include/asm/elf.h	2015-11-11 02:20:02.099077000 +0000
@@ -448,7 +448,7 @@ struct arch_elf_state {
 extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf,
 			    bool is_interp, struct arch_elf_state *state);
 
-extern int arch_check_elf(void *ehdr, bool has_interpreter,
+extern int arch_check_elf(void *ehdr, bool has_interpreter, void *interp_ehdr,
 			  struct arch_elf_state *state);
 
 extern void mips_set_personality_fp(struct arch_elf_state *state);
Index: linux-sfr-test/arch/mips/kernel/elf.c
===================================================================
--- linux-sfr-test.orig/arch/mips/kernel/elf.c	2015-11-11 02:19:56.376032000 +0000
+++ linux-sfr-test/arch/mips/kernel/elf.c	2015-11-11 02:20:02.104077000 +0000
@@ -128,7 +128,7 @@ int arch_elf_pt_proc(void *_ehdr, void *
 	return 0;
 }
 
-int arch_check_elf(void *_ehdr, bool has_interpreter,
+int arch_check_elf(void *_ehdr, bool has_interpreter, void *_interp_ehdr,
 		   struct arch_elf_state *state)
 {
 	union {
Index: linux-sfr-test/fs/binfmt_elf.c
===================================================================
--- linux-sfr-test.orig/fs/binfmt_elf.c	2015-11-10 18:08:00.126238000 +0000
+++ linux-sfr-test/fs/binfmt_elf.c	2015-11-11 02:20:02.126077000 +0000
@@ -490,6 +490,7 @@ static inline int arch_elf_pt_proc(struc
  * arch_check_elf() - check an ELF executable
  * @ehdr:	The main ELF header
  * @has_interp:	True if the ELF has an interpreter, else false.
+ * @interp_ehdr: The interpreter's ELF header
  * @state:	Architecture-specific state preserved throughout the process
  *		of loading the ELF.
  *
@@ -501,6 +502,7 @@ static inline int arch_elf_pt_proc(struc
  *         with that return code.
  */
 static inline int arch_check_elf(struct elfhdr *ehdr, bool has_interp,
+				 struct elfhdr *interp_ehdr,
 				 struct arch_elf_state *state)
 {
 	/* Dummy implementation, always proceed */
@@ -828,7 +830,9 @@ static int load_elf_binary(struct linux_
 	 * still possible to return an error to the code that invoked
 	 * the exec syscall.
 	 */
-	retval = arch_check_elf(&loc->elf_ex, !!interpreter, &arch_state);
+	retval = arch_check_elf(&loc->elf_ex,
+				!!interpreter, &loc->interp_elf_ex,
+				&arch_state);
 	if (retval)
 		goto out_free_dentry;
 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 5/8] ELF: Also pass any interpreter's file header to `arch_check_elf'
@ 2015-11-13  0:47   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:47 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Also pass any interpreter's file header to `arch_check_elf' so that any 
architecture handler can have a look at it if needed.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
linux-arch-check-elf-interp.diff
Index: linux-sfr-test/arch/mips/include/asm/elf.h
===================================================================
--- linux-sfr-test.orig/arch/mips/include/asm/elf.h	2015-11-10 18:06:16.547399000 +0000
+++ linux-sfr-test/arch/mips/include/asm/elf.h	2015-11-11 02:20:02.099077000 +0000
@@ -448,7 +448,7 @@ struct arch_elf_state {
 extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf,
 			    bool is_interp, struct arch_elf_state *state);
 
-extern int arch_check_elf(void *ehdr, bool has_interpreter,
+extern int arch_check_elf(void *ehdr, bool has_interpreter, void *interp_ehdr,
 			  struct arch_elf_state *state);
 
 extern void mips_set_personality_fp(struct arch_elf_state *state);
Index: linux-sfr-test/arch/mips/kernel/elf.c
===================================================================
--- linux-sfr-test.orig/arch/mips/kernel/elf.c	2015-11-11 02:19:56.376032000 +0000
+++ linux-sfr-test/arch/mips/kernel/elf.c	2015-11-11 02:20:02.104077000 +0000
@@ -128,7 +128,7 @@ int arch_elf_pt_proc(void *_ehdr, void *
 	return 0;
 }
 
-int arch_check_elf(void *_ehdr, bool has_interpreter,
+int arch_check_elf(void *_ehdr, bool has_interpreter, void *_interp_ehdr,
 		   struct arch_elf_state *state)
 {
 	union {
Index: linux-sfr-test/fs/binfmt_elf.c
===================================================================
--- linux-sfr-test.orig/fs/binfmt_elf.c	2015-11-10 18:08:00.126238000 +0000
+++ linux-sfr-test/fs/binfmt_elf.c	2015-11-11 02:20:02.126077000 +0000
@@ -490,6 +490,7 @@ static inline int arch_elf_pt_proc(struc
  * arch_check_elf() - check an ELF executable
  * @ehdr:	The main ELF header
  * @has_interp:	True if the ELF has an interpreter, else false.
+ * @interp_ehdr: The interpreter's ELF header
  * @state:	Architecture-specific state preserved throughout the process
  *		of loading the ELF.
  *
@@ -501,6 +502,7 @@ static inline int arch_elf_pt_proc(struc
  *         with that return code.
  */
 static inline int arch_check_elf(struct elfhdr *ehdr, bool has_interp,
+				 struct elfhdr *interp_ehdr,
 				 struct arch_elf_state *state)
 {
 	/* Dummy implementation, always proceed */
@@ -828,7 +830,9 @@ static int load_elf_binary(struct linux_
 	 * still possible to return an error to the code that invoked
 	 * the exec syscall.
 	 */
-	retval = arch_check_elf(&loc->elf_ex, !!interpreter, &arch_state);
+	retval = arch_check_elf(&loc->elf_ex,
+				!!interpreter, &loc->interp_elf_ex,
+				&arch_state);
 	if (retval)
 		goto out_free_dentry;
 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 6/8] MIPS: ELF: Interpret the NAN2008 file header flag
@ 2015-11-13  0:48   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:48 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Handle the EF_MIPS_NAN2008 ELF file header flag and refuse execution 
where there is no support in the FPU for the NaN encoding mode requested 
by a binary invoked.  Ensure that the setting of the bit in the binary 
matches one in any intepreter used.  Set the thread's initial FCSR 
contents according to the value of the EF_MIPS_NAN2008.

Set the values of the FCSR ABS2008 and NAN2008 bits both to the same 
value if possible, to take the approach taken with existing FPU hardware 
into account.  As of now all implementations have both bits hardwired to 
the same value, that is both are fixed at 0 or both are fixed at 1, even 
though the architecture allows for implementations where the amount of 
control implemented with each of these two individual bits is 
independent of each other.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
This change relies on <https://patchwork.kernel.org/patch/7491081/> to 
work correctly for dynamic binaries, otherwise an opposite-mode 
interpreter will be incorrectly accepted, and worse yet enforce any 
additional shared binaries to have their NaN mode opposite to that of the 
main binary.  This will normally only happen for broken installations or 
incorrectly built binaries where PT_INTERP points to the wrong dynamic 
linker though.  Static binaries are unaffected.

linux-mips-elf-nan2008.diff
Index: linux-sfr-test/arch/mips/include/asm/elf.h
===================================================================
--- linux-sfr-test.orig/arch/mips/include/asm/elf.h	2015-11-11 02:20:02.099077000 +0000
+++ linux-sfr-test/arch/mips/include/asm/elf.h	2015-11-11 02:20:16.030180000 +0000
@@ -12,7 +12,6 @@
 #include <linux/fs.h>
 #include <uapi/linux/elf.h>
 
-#include <asm/cpu-info.h>
 #include <asm/current.h>
 
 /* ELF header e_flags defines. */
@@ -44,6 +43,7 @@
 #define EF_MIPS_OPTIONS_FIRST	0x00000080
 #define EF_MIPS_32BITMODE	0x00000100
 #define EF_MIPS_FP64		0x00000200
+#define EF_MIPS_NAN2008		0x00000400
 #define EF_MIPS_ABI		0x0000f000
 #define EF_MIPS_ARCH		0xf0000000
 
@@ -305,7 +305,7 @@ do {									\
 									\
 	current->thread.abi = &mips_abi;				\
 									\
-	current->thread.fpu.fcr31 = boot_cpu_data.fpu_csr31;		\
+	mips_set_personality_nan(state);				\
 } while (0)
 
 #endif /* CONFIG_32BIT */
@@ -367,7 +367,7 @@ do {									\
 	else								\
 		current->thread.abi = &mips_abi;			\
 									\
-	current->thread.fpu.fcr31 = boot_cpu_data.fpu_csr31;		\
+	mips_set_personality_nan(state);				\
 									\
 	p = personality(current->personality);				\
 	if (p != PER_LINUX32 && p != PER_LINUX)				\
@@ -432,6 +432,7 @@ extern int arch_setup_additional_pages(s
 				       int uses_interp);
 
 struct arch_elf_state {
+	int nan_2008;
 	int fp_abi;
 	int interp_fp_abi;
 	int overall_fp_mode;
@@ -440,6 +441,7 @@ struct arch_elf_state {
 #define MIPS_ABI_FP_UNKNOWN	(-1)	/* Unknown FP ABI (kernel internal) */
 
 #define INIT_ARCH_ELF_STATE {			\
+	.nan_2008 = -1,				\
 	.fp_abi = MIPS_ABI_FP_UNKNOWN,		\
 	.interp_fp_abi = MIPS_ABI_FP_UNKNOWN,	\
 	.overall_fp_mode = -1,			\
@@ -451,6 +453,7 @@ extern int arch_elf_pt_proc(void *ehdr, 
 extern int arch_check_elf(void *ehdr, bool has_interpreter, void *interp_ehdr,
 			  struct arch_elf_state *state);
 
+extern void mips_set_personality_nan(struct arch_elf_state *state);
 extern void mips_set_personality_fp(struct arch_elf_state *state);
 
 #endif /* _ASM_ELF_H */
Index: linux-sfr-test/arch/mips/kernel/elf.c
===================================================================
--- linux-sfr-test.orig/arch/mips/kernel/elf.c	2015-11-11 02:20:02.104077000 +0000
+++ linux-sfr-test/arch/mips/kernel/elf.c	2015-11-11 02:20:16.033179000 +0000
@@ -11,6 +11,8 @@
 #include <linux/elf.h>
 #include <linux/sched.h>
 
+#include <asm/cpu-info.h>
+
 /* FPU modes */
 enum {
 	FP_FRE,
@@ -135,6 +137,10 @@ int arch_check_elf(void *_ehdr, bool has
 		struct elf32_hdr e32;
 		struct elf64_hdr e64;
 	} *ehdr = _ehdr;
+	union {
+		struct elf32_hdr e32;
+		struct elf64_hdr e64;
+	} *iehdr = _interp_ehdr;
 	struct mode_req prog_req, interp_req;
 	int fp_abi, interp_fp_abi, abi0, abi1, max_abi;
 	bool elf32;
@@ -143,6 +149,32 @@ int arch_check_elf(void *_ehdr, bool has
 	elf32 = ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32;
 	flags = elf32 ? ehdr->e32.e_flags : ehdr->e64.e_flags;
 
+	/*
+	 * Determine the NaN personality, reject the binary if no hardware
+	 * support.  Also ensure that any interpreter matches the executable.
+	 */
+	if (flags & EF_MIPS_NAN2008) {
+		if (cpu_has_nan_2008)
+			state->nan_2008 = 1;
+		else
+			return -ENOEXEC;
+	} else {
+		if (cpu_has_nan_legacy)
+			state->nan_2008 = 0;
+		else
+			return -ENOEXEC;
+	}
+	if (has_interpreter) {
+		bool ielf32;
+		u32 iflags;
+
+		ielf32 = iehdr->e32.e_ident[EI_CLASS] == ELFCLASS32;
+		iflags = ielf32 ? iehdr->e32.e_flags : iehdr->e64.e_flags;
+
+		if ((flags ^ iflags) & EF_MIPS_NAN2008)
+			return -ELIBBAD;
+	}
+
 	if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
 		return 0;
 
@@ -266,3 +298,27 @@ void mips_set_personality_fp(struct arch
 		BUG();
 	}
 }
+
+/*
+ * Select the IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode
+ * in FCSR according to the ELF NaN personality.
+ */
+void mips_set_personality_nan(struct arch_elf_state *state)
+{
+	struct cpuinfo_mips *c = &boot_cpu_data;
+	struct task_struct *t = current;
+
+	t->thread.fpu.fcr31 = c->fpu_csr31;
+	switch (state->nan_2008) {
+	case 0:
+		break;
+	case 1:
+		if (!(c->fpu_msk31 & FPU_CSR_NAN2008))
+			t->thread.fpu.fcr31 |= FPU_CSR_NAN2008;
+		if (!(c->fpu_msk31 & FPU_CSR_ABS2008))
+			t->thread.fpu.fcr31 |= FPU_CSR_ABS2008;
+		break;
+	default:
+		BUG();
+	}
+}

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 6/8] MIPS: ELF: Interpret the NAN2008 file header flag
@ 2015-11-13  0:48   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:48 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Handle the EF_MIPS_NAN2008 ELF file header flag and refuse execution 
where there is no support in the FPU for the NaN encoding mode requested 
by a binary invoked.  Ensure that the setting of the bit in the binary 
matches one in any intepreter used.  Set the thread's initial FCSR 
contents according to the value of the EF_MIPS_NAN2008.

Set the values of the FCSR ABS2008 and NAN2008 bits both to the same 
value if possible, to take the approach taken with existing FPU hardware 
into account.  As of now all implementations have both bits hardwired to 
the same value, that is both are fixed at 0 or both are fixed at 1, even 
though the architecture allows for implementations where the amount of 
control implemented with each of these two individual bits is 
independent of each other.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
This change relies on <https://patchwork.kernel.org/patch/7491081/> to 
work correctly for dynamic binaries, otherwise an opposite-mode 
interpreter will be incorrectly accepted, and worse yet enforce any 
additional shared binaries to have their NaN mode opposite to that of the 
main binary.  This will normally only happen for broken installations or 
incorrectly built binaries where PT_INTERP points to the wrong dynamic 
linker though.  Static binaries are unaffected.

linux-mips-elf-nan2008.diff
Index: linux-sfr-test/arch/mips/include/asm/elf.h
===================================================================
--- linux-sfr-test.orig/arch/mips/include/asm/elf.h	2015-11-11 02:20:02.099077000 +0000
+++ linux-sfr-test/arch/mips/include/asm/elf.h	2015-11-11 02:20:16.030180000 +0000
@@ -12,7 +12,6 @@
 #include <linux/fs.h>
 #include <uapi/linux/elf.h>
 
-#include <asm/cpu-info.h>
 #include <asm/current.h>
 
 /* ELF header e_flags defines. */
@@ -44,6 +43,7 @@
 #define EF_MIPS_OPTIONS_FIRST	0x00000080
 #define EF_MIPS_32BITMODE	0x00000100
 #define EF_MIPS_FP64		0x00000200
+#define EF_MIPS_NAN2008		0x00000400
 #define EF_MIPS_ABI		0x0000f000
 #define EF_MIPS_ARCH		0xf0000000
 
@@ -305,7 +305,7 @@ do {									\
 									\
 	current->thread.abi = &mips_abi;				\
 									\
-	current->thread.fpu.fcr31 = boot_cpu_data.fpu_csr31;		\
+	mips_set_personality_nan(state);				\
 } while (0)
 
 #endif /* CONFIG_32BIT */
@@ -367,7 +367,7 @@ do {									\
 	else								\
 		current->thread.abi = &mips_abi;			\
 									\
-	current->thread.fpu.fcr31 = boot_cpu_data.fpu_csr31;		\
+	mips_set_personality_nan(state);				\
 									\
 	p = personality(current->personality);				\
 	if (p != PER_LINUX32 && p != PER_LINUX)				\
@@ -432,6 +432,7 @@ extern int arch_setup_additional_pages(s
 				       int uses_interp);
 
 struct arch_elf_state {
+	int nan_2008;
 	int fp_abi;
 	int interp_fp_abi;
 	int overall_fp_mode;
@@ -440,6 +441,7 @@ struct arch_elf_state {
 #define MIPS_ABI_FP_UNKNOWN	(-1)	/* Unknown FP ABI (kernel internal) */
 
 #define INIT_ARCH_ELF_STATE {			\
+	.nan_2008 = -1,				\
 	.fp_abi = MIPS_ABI_FP_UNKNOWN,		\
 	.interp_fp_abi = MIPS_ABI_FP_UNKNOWN,	\
 	.overall_fp_mode = -1,			\
@@ -451,6 +453,7 @@ extern int arch_elf_pt_proc(void *ehdr, 
 extern int arch_check_elf(void *ehdr, bool has_interpreter, void *interp_ehdr,
 			  struct arch_elf_state *state);
 
+extern void mips_set_personality_nan(struct arch_elf_state *state);
 extern void mips_set_personality_fp(struct arch_elf_state *state);
 
 #endif /* _ASM_ELF_H */
Index: linux-sfr-test/arch/mips/kernel/elf.c
===================================================================
--- linux-sfr-test.orig/arch/mips/kernel/elf.c	2015-11-11 02:20:02.104077000 +0000
+++ linux-sfr-test/arch/mips/kernel/elf.c	2015-11-11 02:20:16.033179000 +0000
@@ -11,6 +11,8 @@
 #include <linux/elf.h>
 #include <linux/sched.h>
 
+#include <asm/cpu-info.h>
+
 /* FPU modes */
 enum {
 	FP_FRE,
@@ -135,6 +137,10 @@ int arch_check_elf(void *_ehdr, bool has
 		struct elf32_hdr e32;
 		struct elf64_hdr e64;
 	} *ehdr = _ehdr;
+	union {
+		struct elf32_hdr e32;
+		struct elf64_hdr e64;
+	} *iehdr = _interp_ehdr;
 	struct mode_req prog_req, interp_req;
 	int fp_abi, interp_fp_abi, abi0, abi1, max_abi;
 	bool elf32;
@@ -143,6 +149,32 @@ int arch_check_elf(void *_ehdr, bool has
 	elf32 = ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32;
 	flags = elf32 ? ehdr->e32.e_flags : ehdr->e64.e_flags;
 
+	/*
+	 * Determine the NaN personality, reject the binary if no hardware
+	 * support.  Also ensure that any interpreter matches the executable.
+	 */
+	if (flags & EF_MIPS_NAN2008) {
+		if (cpu_has_nan_2008)
+			state->nan_2008 = 1;
+		else
+			return -ENOEXEC;
+	} else {
+		if (cpu_has_nan_legacy)
+			state->nan_2008 = 0;
+		else
+			return -ENOEXEC;
+	}
+	if (has_interpreter) {
+		bool ielf32;
+		u32 iflags;
+
+		ielf32 = iehdr->e32.e_ident[EI_CLASS] == ELFCLASS32;
+		iflags = ielf32 ? iehdr->e32.e_flags : iehdr->e64.e_flags;
+
+		if ((flags ^ iflags) & EF_MIPS_NAN2008)
+			return -ELIBBAD;
+	}
+
 	if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
 		return 0;
 
@@ -266,3 +298,27 @@ void mips_set_personality_fp(struct arch
 		BUG();
 	}
 }
+
+/*
+ * Select the IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode
+ * in FCSR according to the ELF NaN personality.
+ */
+void mips_set_personality_nan(struct arch_elf_state *state)
+{
+	struct cpuinfo_mips *c = &boot_cpu_data;
+	struct task_struct *t = current;
+
+	t->thread.fpu.fcr31 = c->fpu_csr31;
+	switch (state->nan_2008) {
+	case 0:
+		break;
+	case 1:
+		if (!(c->fpu_msk31 & FPU_CSR_NAN2008))
+			t->thread.fpu.fcr31 |= FPU_CSR_NAN2008;
+		if (!(c->fpu_msk31 & FPU_CSR_ABS2008))
+			t->thread.fpu.fcr31 |= FPU_CSR_ABS2008;
+		break;
+	default:
+		BUG();
+	}
+}

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 7/8] MIPS: Determine the presence of IEEE Std 754-2008 features
@ 2015-11-13  0:48   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:48 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Determine the presence of and the amount of control available over IEEE 
Std 754-2008 features.

In the case of a hardware FPU being used examine the FIR register for 
the presence of the HAS2008 bit and then the FCSR register for the 
writability of the ABS2008 and NAN2008 bits and the hardwired state of 
each of these bits if read-only.  Update the initial FCSR contents used 
for threads and the FCSR writability mask accordingly.

For full FPU emulation and MIPS32 or MIPS64 processors make the FCSR 
ABS2008 and NAN2008 bits writable.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
linux-mips-cpu-nan2008.diff
Index: linux-sfr-test/arch/mips/kernel/cpu-probe.c
===================================================================
--- linux-sfr-test.orig/arch/mips/kernel/cpu-probe.c	2015-09-04 21:35:56.582838000 +0100
+++ linux-sfr-test/arch/mips/kernel/cpu-probe.c	2015-09-04 21:36:39.738114000 +0100
@@ -99,6 +99,78 @@ static inline void cpu_set_fpu_fcsr_mask
 }
 
 /*
+ * Determine the IEEE 754 NaN encodings and ABS.fmt/NEG.fmt execution modes
+ * supported by FPU hardware.
+ */
+static void cpu_set_fpu_2008(struct cpuinfo_mips *c)
+{
+	if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
+			    MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
+			    MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) {
+		unsigned long sr, fir, fcsr, fcsr0, fcsr1;
+
+		sr = read_c0_status();
+		__enable_fpu(FPU_AS_IS);
+
+		fir = read_32bit_cp1_register(CP1_REVISION);
+		if (fir & MIPS_FPIR_HAS2008) {
+			fcsr = read_32bit_cp1_register(CP1_STATUS);
+
+			fcsr0 = fcsr & ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
+			write_32bit_cp1_register(CP1_STATUS, fcsr0);
+			fcsr0 = read_32bit_cp1_register(CP1_STATUS);
+
+			fcsr1 = fcsr | FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
+			write_32bit_cp1_register(CP1_STATUS, fcsr1);
+			fcsr1 = read_32bit_cp1_register(CP1_STATUS);
+
+			write_32bit_cp1_register(CP1_STATUS, fcsr);
+
+			if (!(fcsr0 & FPU_CSR_NAN2008))
+				c->options |= MIPS_CPU_NAN_LEGACY;
+			if (fcsr1 & FPU_CSR_NAN2008)
+				c->options |= MIPS_CPU_NAN_2008;
+
+			if ((fcsr0 ^ fcsr1) & FPU_CSR_ABS2008)
+				c->fpu_msk31 &= ~FPU_CSR_ABS2008;
+			else
+				c->fpu_csr31 |= fcsr & FPU_CSR_ABS2008;
+
+			if ((fcsr0 ^ fcsr1) & FPU_CSR_NAN2008)
+				c->fpu_msk31 &= ~FPU_CSR_NAN2008;
+			else
+				c->fpu_csr31 |= fcsr & FPU_CSR_NAN2008;
+		} else {
+			c->options |= MIPS_CPU_NAN_LEGACY;
+		}
+
+		write_c0_status(sr);
+	} else {
+		c->options |= MIPS_CPU_NAN_LEGACY;
+	}
+}
+
+/*
+ * Set the IEEE 754 NaN encodings and ABS.fmt/NEG.fmt execution modes
+ * for the FPU emulator.  Clear the flags where required in case called
+ * from `fpu_disable', to override details obtained from FPU hardware.
+ */
+static void cpu_set_nofpu_2008(struct cpuinfo_mips *c)
+{
+	c->fpu_csr31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
+	if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
+			    MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
+			    MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) {
+		c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY;
+		c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
+	} else {
+		c->options &= ~MIPS_CPU_NAN_2008;
+		c->options |= MIPS_CPU_NAN_LEGACY;
+		c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
+	}
+}
+
+/*
  * Set the FIR feature flags for the FPU emulator.
  */
 static void cpu_set_nofpu_id(struct cpuinfo_mips *c)
@@ -139,7 +211,7 @@ static void cpu_set_fpu_opts(struct cpui
 	}
 
 	cpu_set_fpu_fcsr_mask(c);
-	c->options |= MIPS_CPU_NAN_LEGACY;
+	cpu_set_fpu_2008(c);
 }
 
 /*
@@ -150,7 +222,7 @@ static void cpu_set_nofpu_opts(struct cp
 	c->options &= ~MIPS_CPU_FPU;
 	c->fpu_msk31 = mips_nofpu_msk31;
 
-	c->options |= MIPS_CPU_NAN_LEGACY;
+	cpu_set_nofpu_2008(c);
 	cpu_set_nofpu_id(c);
 }
 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 7/8] MIPS: Determine the presence of IEEE Std 754-2008 features
@ 2015-11-13  0:48   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:48 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Determine the presence of and the amount of control available over IEEE 
Std 754-2008 features.

In the case of a hardware FPU being used examine the FIR register for 
the presence of the HAS2008 bit and then the FCSR register for the 
writability of the ABS2008 and NAN2008 bits and the hardwired state of 
each of these bits if read-only.  Update the initial FCSR contents used 
for threads and the FCSR writability mask accordingly.

For full FPU emulation and MIPS32 or MIPS64 processors make the FCSR 
ABS2008 and NAN2008 bits writable.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
linux-mips-cpu-nan2008.diff
Index: linux-sfr-test/arch/mips/kernel/cpu-probe.c
===================================================================
--- linux-sfr-test.orig/arch/mips/kernel/cpu-probe.c	2015-09-04 21:35:56.582838000 +0100
+++ linux-sfr-test/arch/mips/kernel/cpu-probe.c	2015-09-04 21:36:39.738114000 +0100
@@ -99,6 +99,78 @@ static inline void cpu_set_fpu_fcsr_mask
 }
 
 /*
+ * Determine the IEEE 754 NaN encodings and ABS.fmt/NEG.fmt execution modes
+ * supported by FPU hardware.
+ */
+static void cpu_set_fpu_2008(struct cpuinfo_mips *c)
+{
+	if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
+			    MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
+			    MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) {
+		unsigned long sr, fir, fcsr, fcsr0, fcsr1;
+
+		sr = read_c0_status();
+		__enable_fpu(FPU_AS_IS);
+
+		fir = read_32bit_cp1_register(CP1_REVISION);
+		if (fir & MIPS_FPIR_HAS2008) {
+			fcsr = read_32bit_cp1_register(CP1_STATUS);
+
+			fcsr0 = fcsr & ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
+			write_32bit_cp1_register(CP1_STATUS, fcsr0);
+			fcsr0 = read_32bit_cp1_register(CP1_STATUS);
+
+			fcsr1 = fcsr | FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
+			write_32bit_cp1_register(CP1_STATUS, fcsr1);
+			fcsr1 = read_32bit_cp1_register(CP1_STATUS);
+
+			write_32bit_cp1_register(CP1_STATUS, fcsr);
+
+			if (!(fcsr0 & FPU_CSR_NAN2008))
+				c->options |= MIPS_CPU_NAN_LEGACY;
+			if (fcsr1 & FPU_CSR_NAN2008)
+				c->options |= MIPS_CPU_NAN_2008;
+
+			if ((fcsr0 ^ fcsr1) & FPU_CSR_ABS2008)
+				c->fpu_msk31 &= ~FPU_CSR_ABS2008;
+			else
+				c->fpu_csr31 |= fcsr & FPU_CSR_ABS2008;
+
+			if ((fcsr0 ^ fcsr1) & FPU_CSR_NAN2008)
+				c->fpu_msk31 &= ~FPU_CSR_NAN2008;
+			else
+				c->fpu_csr31 |= fcsr & FPU_CSR_NAN2008;
+		} else {
+			c->options |= MIPS_CPU_NAN_LEGACY;
+		}
+
+		write_c0_status(sr);
+	} else {
+		c->options |= MIPS_CPU_NAN_LEGACY;
+	}
+}
+
+/*
+ * Set the IEEE 754 NaN encodings and ABS.fmt/NEG.fmt execution modes
+ * for the FPU emulator.  Clear the flags where required in case called
+ * from `fpu_disable', to override details obtained from FPU hardware.
+ */
+static void cpu_set_nofpu_2008(struct cpuinfo_mips *c)
+{
+	c->fpu_csr31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
+	if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
+			    MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
+			    MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) {
+		c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY;
+		c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
+	} else {
+		c->options &= ~MIPS_CPU_NAN_2008;
+		c->options |= MIPS_CPU_NAN_LEGACY;
+		c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
+	}
+}
+
+/*
  * Set the FIR feature flags for the FPU emulator.
  */
 static void cpu_set_nofpu_id(struct cpuinfo_mips *c)
@@ -139,7 +211,7 @@ static void cpu_set_fpu_opts(struct cpui
 	}
 
 	cpu_set_fpu_fcsr_mask(c);
-	c->options |= MIPS_CPU_NAN_LEGACY;
+	cpu_set_fpu_2008(c);
 }
 
 /*
@@ -150,7 +222,7 @@ static void cpu_set_nofpu_opts(struct cp
 	c->options &= ~MIPS_CPU_FPU;
 	c->fpu_msk31 = mips_nofpu_msk31;
 
-	c->options |= MIPS_CPU_NAN_LEGACY;
+	cpu_set_nofpu_2008(c);
 	cpu_set_nofpu_id(c);
 }
 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 8/8] MIPS: Add IEEE Std 754 conformance mode selection
@ 2015-11-13  0:48   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:48 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Add an `ieee754=' kernel parameter to control IEEE Std 754 conformance 
mode.

Use separate flags copied from the respective CPU feature flags, and 
adjusted according to the conformance mode selected, to make binaries 
requesting individual NaN encoding modes accepted or rejected as needed.  
Update the initial setting for FCSR and, in the full FPU emulation mode, 
its read-only mask accordingly.  Accept the mode selection requested for 
legacy processors as well.

As with the EF_MIPS_NAN2008 ELF file header flag adjust both ABS2008 and
NAN2008 bits at the same time, to match the choice made for hardware 
currently implemented.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
linux-mips-arg-ieee754.diff
Index: linux-sfr-test/Documentation/kernel-parameters.txt
===================================================================
--- linux-sfr-test.orig/Documentation/kernel-parameters.txt	2015-11-10 17:45:24.154444000 +0000
+++ linux-sfr-test/Documentation/kernel-parameters.txt	2015-11-11 02:20:23.310234000 +0000
@@ -1399,6 +1399,41 @@ bytes respectively. Such letter suffixes
 			In such case C2/C3 won't be used again.
 			idle=nomwait: Disable mwait for CPU C-states
 
+	ieee754=	[MIPS] Select IEEE Std 754 conformance mode
+			Format: { strict | legacy | 2008 | relaxed }
+			Default: strict
+
+			Choose which programs will be accepted for execution
+			based on the IEEE 754 NaN encoding(s) supported by
+			the FPU and the NaN encoding requested with the value
+			of an ELF file header flag individually set by each
+			binary.  Hardware implementations are permitted to
+			support either or both of the legacy and the 2008 NaN
+			encoding mode.
+
+			Available settings are as follows:
+			strict	accept binaries that request a NaN encoding
+				supported by the FPU
+			legacy	only accept legacy-NaN binaries, if supported
+				by the FPU
+			2008	only accept 2008-NaN binaries, if supported
+				by the FPU
+			relaxed	accept any binaries regardless of whether
+				supported by the FPU
+
+			The FPU emulator is always able to support both NaN
+			encodings, so if no FPU hardware is present or it has
+			been disabled with 'nofpu', then the settings of
+			'legacy' and '2008' strap the emulator accordingly,
+			'relaxed' straps the emulator for both legacy-NaN and
+			2008-NaN, whereas 'strict' enables legacy-NaN only on
+			legacy processors and both NaN encodings on MIPS32 or
+			MIPS64 CPUs.
+
+			The setting for ABS.fmt/NEG.fmt instruction execution
+			mode generally follows that for the NaN encoding,
+			except where unsupported by hardware.
+
 	ignore_loglevel	[KNL]
 			Ignore loglevel setting - this will print /all/
 			kernel messages to the console. Useful for debugging.
Index: linux-sfr-test/arch/mips/include/asm/elf.h
===================================================================
--- linux-sfr-test.orig/arch/mips/include/asm/elf.h	2015-11-11 02:20:16.030180000 +0000
+++ linux-sfr-test/arch/mips/include/asm/elf.h	2015-11-11 02:20:23.314234000 +0000
@@ -447,6 +447,10 @@ struct arch_elf_state {
 	.overall_fp_mode = -1,			\
 }
 
+/* Whether to accept legacy-NaN and 2008-NaN user binaries.  */
+extern bool mips_use_nan_legacy;
+extern bool mips_use_nan_2008;
+
 extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf,
 			    bool is_interp, struct arch_elf_state *state);
 
Index: linux-sfr-test/arch/mips/kernel/cpu-probe.c
===================================================================
--- linux-sfr-test.orig/arch/mips/kernel/cpu-probe.c	2015-11-11 02:20:21.488222000 +0000
+++ linux-sfr-test/arch/mips/kernel/cpu-probe.c	2015-11-11 02:20:23.317237000 +0000
@@ -151,26 +151,109 @@ static void cpu_set_fpu_2008(struct cpui
 }
 
 /*
- * Set the IEEE 754 NaN encodings and ABS.fmt/NEG.fmt execution modes
- * for the FPU emulator.  Clear the flags where required in case called
- * from `fpu_disable', to override details obtained from FPU hardware.
+ * IEEE 754 conformance mode to use.  Affects the NaN encoding and the
+ * ABS.fmt/NEG.fmt execution mode.
+ */
+static enum { STRICT, LEGACY, STD2008, RELAXED } ieee754 = STRICT;
+
+/*
+ * Set the IEEE 754 NaN encodings and the ABS.fmt/NEG.fmt execution modes
+ * to support by the FPU emulator according to the IEEE 754 conformance
+ * mode selected.  Note that "relaxed" straps the emulator so that it
+ * allows 2008-NaN binaries even for legacy processors.
  */
 static void cpu_set_nofpu_2008(struct cpuinfo_mips *c)
 {
+	c->options &= ~(MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY);
 	c->fpu_csr31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
-	if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
-			    MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
-			    MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) {
-		c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY;
-		c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
-	} else {
-		c->options &= ~MIPS_CPU_NAN_2008;
+	c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
+
+	switch (ieee754) {
+	case STRICT:
+		if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
+				    MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
+				    MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) {
+			c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY;
+		} else {
+			c->options |= MIPS_CPU_NAN_LEGACY;
+			c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
+		}
+		break;
+	case LEGACY:
 		c->options |= MIPS_CPU_NAN_LEGACY;
 		c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
+		break;
+	case STD2008:
+		c->options |= MIPS_CPU_NAN_2008;
+		c->fpu_csr31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
+		c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
+		break;
+	case RELAXED:
+		c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY;
+		break;
 	}
 }
 
 /*
+ * Override the IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode
+ * according to the "ieee754=" parameter.
+ */
+static void cpu_set_nan_2008(struct cpuinfo_mips *c)
+{
+	switch (ieee754) {
+	case STRICT:
+		mips_use_nan_legacy = !!cpu_has_nan_legacy;
+		mips_use_nan_2008 = !!cpu_has_nan_2008;
+		break;
+	case LEGACY:
+		mips_use_nan_legacy = !!cpu_has_nan_legacy;
+		mips_use_nan_2008 = !cpu_has_nan_legacy;
+		break;
+	case STD2008:
+		mips_use_nan_legacy = !cpu_has_nan_2008;
+		mips_use_nan_2008 = !!cpu_has_nan_2008;
+		break;
+	case RELAXED:
+		mips_use_nan_legacy = true;
+		mips_use_nan_2008 = true;
+		break;
+	}
+}
+
+/*
+ * IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode override
+ * settings:
+ *
+ * strict:  accept binaries that request a NaN encoding supported by the FPU
+ * legacy:  only accept legacy-NaN binaries
+ * 2008:    only accept 2008-NaN binaries
+ * relaxed: accept any binaries regardless of whether supported by the FPU
+ */
+static int __init ieee754_setup(char *s)
+{
+	if (!s)
+		return -1;
+	else if (!strcmp(s, "strict"))
+		ieee754 = STRICT;
+	else if (!strcmp(s, "legacy"))
+		ieee754 = LEGACY;
+	else if (!strcmp(s, "2008"))
+		ieee754 = STD2008;
+	else if (!strcmp(s, "relaxed"))
+		ieee754 = RELAXED;
+	else
+		return -1;
+
+	if (!(boot_cpu_data.options & MIPS_CPU_FPU))
+		cpu_set_nofpu_2008(&boot_cpu_data);
+	cpu_set_nan_2008(&boot_cpu_data);
+
+	return 0;
+}
+
+early_param("ieee754", ieee754_setup);
+
+/*
  * Set the FIR feature flags for the FPU emulator.
  */
 static void cpu_set_nofpu_id(struct cpuinfo_mips *c)
@@ -212,6 +295,7 @@ static void cpu_set_fpu_opts(struct cpui
 
 	cpu_set_fpu_fcsr_mask(c);
 	cpu_set_fpu_2008(c);
+	cpu_set_nan_2008(c);
 }
 
 /*
@@ -223,6 +307,7 @@ static void cpu_set_nofpu_opts(struct cp
 	c->fpu_msk31 = mips_nofpu_msk31;
 
 	cpu_set_nofpu_2008(c);
+	cpu_set_nan_2008(c);
 	cpu_set_nofpu_id(c);
 }
 
Index: linux-sfr-test/arch/mips/kernel/elf.c
===================================================================
--- linux-sfr-test.orig/arch/mips/kernel/elf.c	2015-11-11 02:20:16.033179000 +0000
+++ linux-sfr-test/arch/mips/kernel/elf.c	2015-11-11 02:20:23.319243000 +0000
@@ -13,6 +13,10 @@
 
 #include <asm/cpu-info.h>
 
+/* Whether to accept legacy-NaN and 2008-NaN user binaries.  */
+bool mips_use_nan_legacy;
+bool mips_use_nan_2008;
+
 /* FPU modes */
 enum {
 	FP_FRE,
@@ -150,16 +154,16 @@ int arch_check_elf(void *_ehdr, bool has
 	flags = elf32 ? ehdr->e32.e_flags : ehdr->e64.e_flags;
 
 	/*
-	 * Determine the NaN personality, reject the binary if no hardware
-	 * support.  Also ensure that any interpreter matches the executable.
+	 * Determine the NaN personality, reject the binary if not allowed.
+	 * Also ensure that any interpreter matches the executable.
 	 */
 	if (flags & EF_MIPS_NAN2008) {
-		if (cpu_has_nan_2008)
+		if (mips_use_nan_2008)
 			state->nan_2008 = 1;
 		else
 			return -ENOEXEC;
 	} else {
-		if (cpu_has_nan_legacy)
+		if (mips_use_nan_legacy)
 			state->nan_2008 = 0;
 		else
 			return -ENOEXEC;

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 8/8] MIPS: Add IEEE Std 754 conformance mode selection
@ 2015-11-13  0:48   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:48 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Add an `ieee754=' kernel parameter to control IEEE Std 754 conformance 
mode.

Use separate flags copied from the respective CPU feature flags, and 
adjusted according to the conformance mode selected, to make binaries 
requesting individual NaN encoding modes accepted or rejected as needed.  
Update the initial setting for FCSR and, in the full FPU emulation mode, 
its read-only mask accordingly.  Accept the mode selection requested for 
legacy processors as well.

As with the EF_MIPS_NAN2008 ELF file header flag adjust both ABS2008 and
NAN2008 bits at the same time, to match the choice made for hardware 
currently implemented.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
linux-mips-arg-ieee754.diff
Index: linux-sfr-test/Documentation/kernel-parameters.txt
===================================================================
--- linux-sfr-test.orig/Documentation/kernel-parameters.txt	2015-11-10 17:45:24.154444000 +0000
+++ linux-sfr-test/Documentation/kernel-parameters.txt	2015-11-11 02:20:23.310234000 +0000
@@ -1399,6 +1399,41 @@ bytes respectively. Such letter suffixes
 			In such case C2/C3 won't be used again.
 			idle=nomwait: Disable mwait for CPU C-states
 
+	ieee754=	[MIPS] Select IEEE Std 754 conformance mode
+			Format: { strict | legacy | 2008 | relaxed }
+			Default: strict
+
+			Choose which programs will be accepted for execution
+			based on the IEEE 754 NaN encoding(s) supported by
+			the FPU and the NaN encoding requested with the value
+			of an ELF file header flag individually set by each
+			binary.  Hardware implementations are permitted to
+			support either or both of the legacy and the 2008 NaN
+			encoding mode.
+
+			Available settings are as follows:
+			strict	accept binaries that request a NaN encoding
+				supported by the FPU
+			legacy	only accept legacy-NaN binaries, if supported
+				by the FPU
+			2008	only accept 2008-NaN binaries, if supported
+				by the FPU
+			relaxed	accept any binaries regardless of whether
+				supported by the FPU
+
+			The FPU emulator is always able to support both NaN
+			encodings, so if no FPU hardware is present or it has
+			been disabled with 'nofpu', then the settings of
+			'legacy' and '2008' strap the emulator accordingly,
+			'relaxed' straps the emulator for both legacy-NaN and
+			2008-NaN, whereas 'strict' enables legacy-NaN only on
+			legacy processors and both NaN encodings on MIPS32 or
+			MIPS64 CPUs.
+
+			The setting for ABS.fmt/NEG.fmt instruction execution
+			mode generally follows that for the NaN encoding,
+			except where unsupported by hardware.
+
 	ignore_loglevel	[KNL]
 			Ignore loglevel setting - this will print /all/
 			kernel messages to the console. Useful for debugging.
Index: linux-sfr-test/arch/mips/include/asm/elf.h
===================================================================
--- linux-sfr-test.orig/arch/mips/include/asm/elf.h	2015-11-11 02:20:16.030180000 +0000
+++ linux-sfr-test/arch/mips/include/asm/elf.h	2015-11-11 02:20:23.314234000 +0000
@@ -447,6 +447,10 @@ struct arch_elf_state {
 	.overall_fp_mode = -1,			\
 }
 
+/* Whether to accept legacy-NaN and 2008-NaN user binaries.  */
+extern bool mips_use_nan_legacy;
+extern bool mips_use_nan_2008;
+
 extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf,
 			    bool is_interp, struct arch_elf_state *state);
 
Index: linux-sfr-test/arch/mips/kernel/cpu-probe.c
===================================================================
--- linux-sfr-test.orig/arch/mips/kernel/cpu-probe.c	2015-11-11 02:20:21.488222000 +0000
+++ linux-sfr-test/arch/mips/kernel/cpu-probe.c	2015-11-11 02:20:23.317237000 +0000
@@ -151,26 +151,109 @@ static void cpu_set_fpu_2008(struct cpui
 }
 
 /*
- * Set the IEEE 754 NaN encodings and ABS.fmt/NEG.fmt execution modes
- * for the FPU emulator.  Clear the flags where required in case called
- * from `fpu_disable', to override details obtained from FPU hardware.
+ * IEEE 754 conformance mode to use.  Affects the NaN encoding and the
+ * ABS.fmt/NEG.fmt execution mode.
+ */
+static enum { STRICT, LEGACY, STD2008, RELAXED } ieee754 = STRICT;
+
+/*
+ * Set the IEEE 754 NaN encodings and the ABS.fmt/NEG.fmt execution modes
+ * to support by the FPU emulator according to the IEEE 754 conformance
+ * mode selected.  Note that "relaxed" straps the emulator so that it
+ * allows 2008-NaN binaries even for legacy processors.
  */
 static void cpu_set_nofpu_2008(struct cpuinfo_mips *c)
 {
+	c->options &= ~(MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY);
 	c->fpu_csr31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
-	if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
-			    MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
-			    MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) {
-		c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY;
-		c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
-	} else {
-		c->options &= ~MIPS_CPU_NAN_2008;
+	c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
+
+	switch (ieee754) {
+	case STRICT:
+		if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
+				    MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
+				    MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) {
+			c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY;
+		} else {
+			c->options |= MIPS_CPU_NAN_LEGACY;
+			c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
+		}
+		break;
+	case LEGACY:
 		c->options |= MIPS_CPU_NAN_LEGACY;
 		c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
+		break;
+	case STD2008:
+		c->options |= MIPS_CPU_NAN_2008;
+		c->fpu_csr31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
+		c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
+		break;
+	case RELAXED:
+		c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY;
+		break;
 	}
 }
 
 /*
+ * Override the IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode
+ * according to the "ieee754=" parameter.
+ */
+static void cpu_set_nan_2008(struct cpuinfo_mips *c)
+{
+	switch (ieee754) {
+	case STRICT:
+		mips_use_nan_legacy = !!cpu_has_nan_legacy;
+		mips_use_nan_2008 = !!cpu_has_nan_2008;
+		break;
+	case LEGACY:
+		mips_use_nan_legacy = !!cpu_has_nan_legacy;
+		mips_use_nan_2008 = !cpu_has_nan_legacy;
+		break;
+	case STD2008:
+		mips_use_nan_legacy = !cpu_has_nan_2008;
+		mips_use_nan_2008 = !!cpu_has_nan_2008;
+		break;
+	case RELAXED:
+		mips_use_nan_legacy = true;
+		mips_use_nan_2008 = true;
+		break;
+	}
+}
+
+/*
+ * IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode override
+ * settings:
+ *
+ * strict:  accept binaries that request a NaN encoding supported by the FPU
+ * legacy:  only accept legacy-NaN binaries
+ * 2008:    only accept 2008-NaN binaries
+ * relaxed: accept any binaries regardless of whether supported by the FPU
+ */
+static int __init ieee754_setup(char *s)
+{
+	if (!s)
+		return -1;
+	else if (!strcmp(s, "strict"))
+		ieee754 = STRICT;
+	else if (!strcmp(s, "legacy"))
+		ieee754 = LEGACY;
+	else if (!strcmp(s, "2008"))
+		ieee754 = STD2008;
+	else if (!strcmp(s, "relaxed"))
+		ieee754 = RELAXED;
+	else
+		return -1;
+
+	if (!(boot_cpu_data.options & MIPS_CPU_FPU))
+		cpu_set_nofpu_2008(&boot_cpu_data);
+	cpu_set_nan_2008(&boot_cpu_data);
+
+	return 0;
+}
+
+early_param("ieee754", ieee754_setup);
+
+/*
  * Set the FIR feature flags for the FPU emulator.
  */
 static void cpu_set_nofpu_id(struct cpuinfo_mips *c)
@@ -212,6 +295,7 @@ static void cpu_set_fpu_opts(struct cpui
 
 	cpu_set_fpu_fcsr_mask(c);
 	cpu_set_fpu_2008(c);
+	cpu_set_nan_2008(c);
 }
 
 /*
@@ -223,6 +307,7 @@ static void cpu_set_nofpu_opts(struct cp
 	c->fpu_msk31 = mips_nofpu_msk31;
 
 	cpu_set_nofpu_2008(c);
+	cpu_set_nan_2008(c);
 	cpu_set_nofpu_id(c);
 }
 
Index: linux-sfr-test/arch/mips/kernel/elf.c
===================================================================
--- linux-sfr-test.orig/arch/mips/kernel/elf.c	2015-11-11 02:20:16.033179000 +0000
+++ linux-sfr-test/arch/mips/kernel/elf.c	2015-11-11 02:20:23.319243000 +0000
@@ -13,6 +13,10 @@
 
 #include <asm/cpu-info.h>
 
+/* Whether to accept legacy-NaN and 2008-NaN user binaries.  */
+bool mips_use_nan_legacy;
+bool mips_use_nan_2008;
+
 /* FPU modes */
 enum {
 	FP_FRE,
@@ -150,16 +154,16 @@ int arch_check_elf(void *_ehdr, bool has
 	flags = elf32 ? ehdr->e32.e_flags : ehdr->e64.e_flags;
 
 	/*
-	 * Determine the NaN personality, reject the binary if no hardware
-	 * support.  Also ensure that any interpreter matches the executable.
+	 * Determine the NaN personality, reject the binary if not allowed.
+	 * Also ensure that any interpreter matches the executable.
 	 */
 	if (flags & EF_MIPS_NAN2008) {
-		if (cpu_has_nan_2008)
+		if (mips_use_nan_2008)
 			state->nan_2008 = 1;
 		else
 			return -ENOEXEC;
 	} else {
-		if (cpu_has_nan_legacy)
+		if (mips_use_nan_legacy)
 			state->nan_2008 = 0;
 		else
 			return -ENOEXEC;

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH] MIPS: ELF: Restructure personality macros
@ 2015-11-13  0:48   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:48 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Update the ELF personality macros used for individual ABIs to make 
actions in the same order across all of them and match formatting too.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
linux-mips-set-personality-shuffle.diff
Index: linux-sfr-test/arch/mips/include/asm/elf.h
===================================================================
--- linux-sfr-test.orig/arch/mips/include/asm/elf.h	2015-11-11 02:20:23.314234000 +0000
+++ linux-sfr-test/arch/mips/include/asm/elf.h	2015-11-11 02:20:27.589266000 +0000
@@ -295,17 +295,16 @@ extern struct mips_abi mips_abi_n32;
 
 #define SET_PERSONALITY2(ex, state)					\
 do {									\
-	if (personality(current->personality) != PER_LINUX)		\
-		set_personality(PER_LINUX);				\
-									\
 	clear_thread_flag(TIF_HYBRID_FPREGS);				\
 	set_thread_flag(TIF_32BIT_FPREGS);				\
 									\
-	mips_set_personality_fp(state);					\
-									\
 	current->thread.abi = &mips_abi;				\
 									\
+	mips_set_personality_fp(state);					\
 	mips_set_personality_nan(state);				\
+									\
+	if (personality(current->personality) != PER_LINUX)		\
+		set_personality(PER_LINUX);				\
 } while (0)
 
 #endif /* CONFIG_32BIT */
@@ -316,6 +315,7 @@ do {									\
 #define __SET_PERSONALITY32_N32()					\
 	do {								\
 		set_thread_flag(TIF_32BIT_ADDR);			\
+									\
 		current->thread.abi = &mips_abi_n32;			\
 	} while (0)
 #else
@@ -331,9 +331,9 @@ do {									\
 		clear_thread_flag(TIF_HYBRID_FPREGS);			\
 		set_thread_flag(TIF_32BIT_FPREGS);			\
 									\
-		mips_set_personality_fp(state);				\
-									\
 		current->thread.abi = &mips_abi_32;			\
+									\
+		mips_set_personality_fp(state);				\
 	} while (0)
 #else
 #define __SET_PERSONALITY32_O32(ex, state)				\

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH] MIPS: ELF: Restructure personality macros
@ 2015-11-13  0:48   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:48 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Update the ELF personality macros used for individual ABIs to make 
actions in the same order across all of them and match formatting too.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
linux-mips-set-personality-shuffle.diff
Index: linux-sfr-test/arch/mips/include/asm/elf.h
===================================================================
--- linux-sfr-test.orig/arch/mips/include/asm/elf.h	2015-11-11 02:20:23.314234000 +0000
+++ linux-sfr-test/arch/mips/include/asm/elf.h	2015-11-11 02:20:27.589266000 +0000
@@ -295,17 +295,16 @@ extern struct mips_abi mips_abi_n32;
 
 #define SET_PERSONALITY2(ex, state)					\
 do {									\
-	if (personality(current->personality) != PER_LINUX)		\
-		set_personality(PER_LINUX);				\
-									\
 	clear_thread_flag(TIF_HYBRID_FPREGS);				\
 	set_thread_flag(TIF_32BIT_FPREGS);				\
 									\
-	mips_set_personality_fp(state);					\
-									\
 	current->thread.abi = &mips_abi;				\
 									\
+	mips_set_personality_fp(state);					\
 	mips_set_personality_nan(state);				\
+									\
+	if (personality(current->personality) != PER_LINUX)		\
+		set_personality(PER_LINUX);				\
 } while (0)
 
 #endif /* CONFIG_32BIT */
@@ -316,6 +315,7 @@ do {									\
 #define __SET_PERSONALITY32_N32()					\
 	do {								\
 		set_thread_flag(TIF_32BIT_ADDR);			\
+									\
 		current->thread.abi = &mips_abi_n32;			\
 	} while (0)
 #else
@@ -331,9 +331,9 @@ do {									\
 		clear_thread_flag(TIF_HYBRID_FPREGS);			\
 		set_thread_flag(TIF_32BIT_FPREGS);			\
 									\
-		mips_set_personality_fp(state);				\
-									\
 		current->thread.abi = &mips_abi_32;			\
+									\
+		mips_set_personality_fp(state);				\
 	} while (0)
 #else
 #define __SET_PERSONALITY32_O32(ex, state)				\

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH] MIPS: math-emu: Always propagate sNaN payload in quieting
@ 2015-11-13  0:48   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:48 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Propagate sNaN payload in quieting in the legacy-NaN mode as well.  If 
clearing the quiet bit would produce infinity, then set the next lower 
trailing significand field bit, matching the SB-1 and BMIPS5000 hardware 
implementations.  Some other MIPS FPU hardware implementations do 
produce the default qNaN bit pattern instead.

This reverts some changes made for semantics preservation with commit 
dc3ddf42 [MIPS: math-emu: Update sNaN quieting handlers], consequently
bringing back most of the semantics from before commit fdffbafb [Lots of 
FPU bug fixes from Kjeld Borch Egevang.], except from the qNaN produced 
in the infinity case.  Previously the default qNaN bit pattern was 
produced in that case.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
linux-mips-emu-snan-legacy.diff
Index: linux-sfr-perf132-malta-el/arch/mips/math-emu/ieee754dp.c
===================================================================
--- linux-sfr-perf132-malta-el.orig/arch/mips/math-emu/ieee754dp.c	2015-04-08 16:59:18.000000000 +0100
+++ linux-sfr-perf132-malta-el/arch/mips/math-emu/ieee754dp.c	2015-04-08 17:05:29.233752000 +0100
@@ -54,10 +54,13 @@ union ieee754dp __cold ieee754dp_nanxcpt
 	assert(ieee754dp_issnan(r));
 
 	ieee754_setcx(IEEE754_INVALID_OPERATION);
-	if (ieee754_csr.nan2008)
+	if (ieee754_csr.nan2008) {
 		DPMANT(r) |= DP_MBIT(DP_FBITS - 1);
-	else
-		r = ieee754dp_indef();
+	} else {
+		DPMANT(r) &= ~DP_MBIT(DP_FBITS - 1);
+		if (!ieee754dp_isnan(r))
+			DPMANT(r) |= DP_MBIT(DP_FBITS - 2);
+	}
 
 	return r;
 }
Index: linux-sfr-perf132-malta-el/arch/mips/math-emu/ieee754sp.c
===================================================================
--- linux-sfr-perf132-malta-el.orig/arch/mips/math-emu/ieee754sp.c	2015-04-08 16:59:45.000000000 +0100
+++ linux-sfr-perf132-malta-el/arch/mips/math-emu/ieee754sp.c	2015-04-08 17:05:29.235752000 +0100
@@ -54,10 +54,13 @@ union ieee754sp __cold ieee754sp_nanxcpt
 	assert(ieee754sp_issnan(r));
 
 	ieee754_setcx(IEEE754_INVALID_OPERATION);
-	if (ieee754_csr.nan2008)
+	if (ieee754_csr.nan2008) {
 		SPMANT(r) |= SP_MBIT(SP_FBITS - 1);
-	else
-		r = ieee754sp_indef();
+	} else {
+		SPMANT(r) &= ~SP_MBIT(SP_FBITS - 1);
+		if (!ieee754sp_isnan(r))
+			SPMANT(r) |= SP_MBIT(SP_FBITS - 2);
+	}
 
 	return r;
 }

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH] MIPS: math-emu: Always propagate sNaN payload in quieting
@ 2015-11-13  0:48   ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-13  0:48 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

Propagate sNaN payload in quieting in the legacy-NaN mode as well.  If 
clearing the quiet bit would produce infinity, then set the next lower 
trailing significand field bit, matching the SB-1 and BMIPS5000 hardware 
implementations.  Some other MIPS FPU hardware implementations do 
produce the default qNaN bit pattern instead.

This reverts some changes made for semantics preservation with commit 
dc3ddf42 [MIPS: math-emu: Update sNaN quieting handlers], consequently
bringing back most of the semantics from before commit fdffbafb [Lots of 
FPU bug fixes from Kjeld Borch Egevang.], except from the qNaN produced 
in the infinity case.  Previously the default qNaN bit pattern was 
produced in that case.

Signed-off-by: Maciej W. Rozycki <macro@imgtec.com>
---
linux-mips-emu-snan-legacy.diff
Index: linux-sfr-perf132-malta-el/arch/mips/math-emu/ieee754dp.c
===================================================================
--- linux-sfr-perf132-malta-el.orig/arch/mips/math-emu/ieee754dp.c	2015-04-08 16:59:18.000000000 +0100
+++ linux-sfr-perf132-malta-el/arch/mips/math-emu/ieee754dp.c	2015-04-08 17:05:29.233752000 +0100
@@ -54,10 +54,13 @@ union ieee754dp __cold ieee754dp_nanxcpt
 	assert(ieee754dp_issnan(r));
 
 	ieee754_setcx(IEEE754_INVALID_OPERATION);
-	if (ieee754_csr.nan2008)
+	if (ieee754_csr.nan2008) {
 		DPMANT(r) |= DP_MBIT(DP_FBITS - 1);
-	else
-		r = ieee754dp_indef();
+	} else {
+		DPMANT(r) &= ~DP_MBIT(DP_FBITS - 1);
+		if (!ieee754dp_isnan(r))
+			DPMANT(r) |= DP_MBIT(DP_FBITS - 2);
+	}
 
 	return r;
 }
Index: linux-sfr-perf132-malta-el/arch/mips/math-emu/ieee754sp.c
===================================================================
--- linux-sfr-perf132-malta-el.orig/arch/mips/math-emu/ieee754sp.c	2015-04-08 16:59:45.000000000 +0100
+++ linux-sfr-perf132-malta-el/arch/mips/math-emu/ieee754sp.c	2015-04-08 17:05:29.235752000 +0100
@@ -54,10 +54,13 @@ union ieee754sp __cold ieee754sp_nanxcpt
 	assert(ieee754sp_issnan(r));
 
 	ieee754_setcx(IEEE754_INVALID_OPERATION);
-	if (ieee754_csr.nan2008)
+	if (ieee754_csr.nan2008) {
 		SPMANT(r) |= SP_MBIT(SP_FBITS - 1);
-	else
-		r = ieee754sp_indef();
+	} else {
+		SPMANT(r) &= ~SP_MBIT(SP_FBITS - 1);
+		if (!ieee754sp_isnan(r))
+			SPMANT(r) |= SP_MBIT(SP_FBITS - 2);
+	}
 
 	return r;
 }

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 6/8] MIPS: ELF: Interpret the NAN2008 file header flag
@ 2015-11-25 17:43     ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-25 17:43 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

On Fri, 13 Nov 2015, Maciej W. Rozycki wrote:

> This change relies on <https://patchwork.kernel.org/patch/7491081/> to 
> work correctly for dynamic binaries, otherwise an opposite-mode 
> interpreter will be incorrectly accepted, and worse yet enforce any 
> additional shared binaries to have their NaN mode opposite to that of the 
> main binary.  This will normally only happen for broken installations or 
> incorrectly built binaries where PT_INTERP points to the wrong dynamic 
> linker though.  Static binaries are unaffected.

 Ralf, I see that patch has now been applied, commit b582ef5c, and no 
concerns have been raised as to the changes considered here so you can 
give this series a go-ahead at your earliest convenience.  Unless someone 
chimes in at the last minute, that is.

 I'll be rather happy if you can push it through in time for 4.4 so that a 
corresponding change required for glibc to define the earliest Linux 
version to enable 2008-NaN support from can make it to the 2.23 release, 
scheduled for late Jan to early Feb 2016 according to the usual practice 
(see <http://www.gnu.org/software/libc/libc.html> for the release 
timeline).  A slushy freeze period is likely to start from Jan 1st for the 
glibc code base, but a change to set the minimum Linux version only for a 
feature already included is surely going to be acceptable even then.

  Maciej

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 6/8] MIPS: ELF: Interpret the NAN2008 file header flag
@ 2015-11-25 17:43     ` Maciej W. Rozycki
  0 siblings, 0 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-11-25 17:43 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Andrew Morton, Matthew Fortune, linux-mips, linux-kernel

On Fri, 13 Nov 2015, Maciej W. Rozycki wrote:

> This change relies on <https://patchwork.kernel.org/patch/7491081/> to 
> work correctly for dynamic binaries, otherwise an opposite-mode 
> interpreter will be incorrectly accepted, and worse yet enforce any 
> additional shared binaries to have their NaN mode opposite to that of the 
> main binary.  This will normally only happen for broken installations or 
> incorrectly built binaries where PT_INTERP points to the wrong dynamic 
> linker though.  Static binaries are unaffected.

 Ralf, I see that patch has now been applied, commit b582ef5c, and no 
concerns have been raised as to the changes considered here so you can 
give this series a go-ahead at your earliest convenience.  Unless someone 
chimes in at the last minute, that is.

 I'll be rather happy if you can push it through in time for 4.4 so that a 
corresponding change required for glibc to define the earliest Linux 
version to enable 2008-NaN support from can make it to the 2.23 release, 
scheduled for late Jan to early Feb 2016 according to the usual practice 
(see <http://www.gnu.org/software/libc/libc.html> for the release 
timeline).  A slushy freeze period is likely to start from Jan 1st for the 
glibc code base, but a change to set the minimum Linux version only for a 
feature already included is surely going to be acceptable even then.

  Maciej

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2015-11-25 17:43 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-13  0:46 [PATCH 0/(8+2)] MIPS: IEEE Std 754-2008 features Maciej W. Rozycki
2015-11-13  0:46 ` Maciej W. Rozycki
2015-11-13  0:46 ` [PATCH 1/8] MIPS: Use a union to access the ELF file header Maciej W. Rozycki
2015-11-13  0:46   ` Maciej W. Rozycki
2015-11-13  0:46 ` [PATCH 2/8] MIPS: Define the legacy-NaN and 2008-NaN features Maciej W. Rozycki
2015-11-13  0:46   ` Maciej W. Rozycki
2015-11-13  0:47 ` [PATCH 3/8] MIPS: math-emu: Add IEEE Std 754-2008 ABS.fmt and NEG.fmt emulation Maciej W. Rozycki
2015-11-13  0:47   ` Maciej W. Rozycki
2015-11-13  0:47 ` [PATCH 4/8] MIPS: math-emu: Add IEEE Std 754-2008 NaN encoding emulation Maciej W. Rozycki
2015-11-13  0:47   ` Maciej W. Rozycki
2015-11-13  0:47 ` [PATCH 5/8] ELF: Also pass any interpreter's file header to `arch_check_elf' Maciej W. Rozycki
2015-11-13  0:47   ` Maciej W. Rozycki
2015-11-13  0:48 ` [PATCH 6/8] MIPS: ELF: Interpret the NAN2008 file header flag Maciej W. Rozycki
2015-11-13  0:48   ` Maciej W. Rozycki
2015-11-25 17:43   ` Maciej W. Rozycki
2015-11-25 17:43     ` Maciej W. Rozycki
2015-11-13  0:48 ` [PATCH 7/8] MIPS: Determine the presence of IEEE Std 754-2008 features Maciej W. Rozycki
2015-11-13  0:48   ` Maciej W. Rozycki
2015-11-13  0:48 ` [PATCH 8/8] MIPS: Add IEEE Std 754 conformance mode selection Maciej W. Rozycki
2015-11-13  0:48   ` Maciej W. Rozycki
2015-11-13  0:48 ` [PATCH] MIPS: ELF: Restructure personality macros Maciej W. Rozycki
2015-11-13  0:48   ` Maciej W. Rozycki
2015-11-13  0:48 ` [PATCH] MIPS: math-emu: Always propagate sNaN payload in quieting Maciej W. Rozycki
2015-11-13  0:48   ` Maciej W. Rozycki

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.