Fix setjmp()/longjmp() to save FP registers on ARMv7.
Change-Id: I8ec684c8f8ca1ae58c8feb330b97d1e2b81caeef
diff --git a/libc/arch-arm/bionic/_setjmp.S b/libc/arch-arm/bionic/_setjmp.S
index 6a27af2..5626219 100644
--- a/libc/arch-arm/bionic/_setjmp.S
+++ b/libc/arch-arm/bionic/_setjmp.S
@@ -3,6 +3,7 @@
/*
* Copyright (c) 1997 Mark Brinicombe
+ * Copyright (c) 2010 Android Open Source Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,6 +36,7 @@
#include <machine/asm.h>
#include <machine/setjmp.h>
+#include <machine/cpu-features.h>
/*
* C library -- _setjmp, _longjmp
@@ -51,18 +53,20 @@
ENTRY(_setjmp)
ldr r1, .L_setjmp_magic
- str r1, [r0], #4
-#ifdef SOFTFLOAT
- add r0, r0, #52
-#else
- /* Store fp registers */
- sfm f4, 4, [r0], #48
- /* Store fpsr */
- rfs r1
- str r1, [r0], #0x0004
-#endif /* SOFTFLOAT */
- /* Store integer registers */
- stmia r0, {r4-r14}
+ str r1, [r0, #(_JB_MAGIC * 4)]
+
+ /* Store core registers */
+ add r1, r0, #(_JB_CORE_BASE * 4)
+ stmia r1, {r4-r14}
+
+#ifdef __ARM_HAVE_VFP
+ /* Store floating-point registers */
+ add r1, r0, #(_JB_FLOAT_BASE * 4)
+ vstmia r1, {d8-d15}
+ /* Store floating-point state */
+ fmrx r1, fpscr
+ str r1, [r0, #(_JB_FLOAT_STATE * 4)]
+#endif /* __ARM_HAVE_VFP */
mov r0, #0x00000000
bx lr
@@ -72,21 +76,22 @@
ENTRY(_longjmp)
ldr r2, .L_setjmp_magic
- ldr r3, [r0], #4
+ ldr r3, [r0, #(_JB_MAGIC * 4)]
teq r2, r3
bne botch
-#ifdef SOFTFLOAT
- add r0, r0, #52
-#else
- /* Restore fp registers */
- lfm f4, 4, [r0], #48
- /* Restore fpsr */
- ldr r4, [r0], #0x0004
- wfs r4
-#endif /* SOFTFLOAT */
- /* Restore integer registers */
- ldmia r0, {r4-r14}
+#ifdef __ARM_HAVE_VFP
+ /* Restore floating-point registers */
+ add r2, r0, #(_JB_FLOAT_BASE * 4)
+ vldmia r2, {d8-d15}
+ /* Restore floating-point state */
+ ldr r2, [r0, #(_JB_FLOAT_STATE * 4)]
+ fmxr fpscr, r2
+#endif /* __ARM_HAVE_VFP */
+
+ /* Restore core registers */
+ add r2, r0, #(_JB_CORE_BASE * 4)
+ ldmia r2, {r4-r14}
/* Validate sp and r14 */
teq sp, #0
diff --git a/libc/arch-arm/bionic/setjmp.S b/libc/arch-arm/bionic/setjmp.S
index a9f6ea4..59aff66 100644
--- a/libc/arch-arm/bionic/setjmp.S
+++ b/libc/arch-arm/bionic/setjmp.S
@@ -3,6 +3,7 @@
/*
* Copyright (c) 1997 Mark Brinicombe
+ * Copyright (c) 2010 Android Open Source Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,6 +36,7 @@
#include <machine/asm.h>
#include <machine/setjmp.h>
+#include <machine/cpu-features.h>
/*
* C library -- setjmp, longjmp
@@ -57,24 +59,26 @@
ldmfd sp!, {r0, r14}
/* Store signal mask */
- str r1, [r0, #(25 * 4)]
+ str r1, [r0, #(_JB_SIGMASK * 4)]
ldr r1, .Lsetjmp_magic
- str r1, [r0], #4
+ str r1, [r0, #(_JB_MAGIC * 4)]
-#ifdef SOFTFLOAT
- add r0, r0, #52
-#else
- /* Store fp registers */
- sfm f4, 4, [r0], #48
- /* Store fpsr */
- rfs r1
- str r1, [r0], #0x0004
-#endif /*SOFTFLOAT*/
- /* Store integer registers */
- stmia r0, {r4-r14}
- mov r0, #0x00000000
- bx lr
+ /* Store core registers */
+ add r1, r0, #(_JB_CORE_BASE * 4)
+ stmia r1, {r4-r14}
+
+#ifdef __ARM_HAVE_VFP
+ /* Store floating-point registers */
+ add r1, r0, #(_JB_FLOAT_BASE * 4)
+ vstmia r1, {d8-d15}
+ /* Store floating-point state */
+ fmrx r1, fpscr
+ str r1, [r0, #(_JB_FLOAT_STATE * 4)]
+#endif /* __ARM_HAVE_VFP */
+
+ mov r0, #0x00000000
+ bx lr
.Lsetjmp_magic:
.word _JB_MAGIC_SETJMP
@@ -82,12 +86,12 @@
ENTRY(longjmp)
ldr r2, .Lsetjmp_magic
- ldr r3, [r0]
+ ldr r3, [r0, #(_JB_MAGIC * 4)]
teq r2, r3
bne botch
/* Fetch signal mask */
- ldr r2, [r0, #(25 * 4)]
+ ldr r2, [r0, #(_JB_SIGMASK * 4)]
/* Set signal mask */
stmfd sp!, {r0, r1, r14}
@@ -99,18 +103,18 @@
add sp, sp, #4 /* unalign the stack */
ldmfd sp!, {r0, r1, r14}
- add r0, r0, #4
-#ifdef SOFTFLOAT
- add r0, r0, #52
-#else
- /* Restore fp registers */
- lfm f4, 4, [r0], #48
- /* Restore FPSR */
- ldr r4, [r0], #0x0004
- wfs r4
-#endif /* SOFTFLOAT */
- /* Restore integer registers */
- ldmia r0, {r4-r14}
+#ifdef __ARM_HAVE_VFP
+ /* Restore floating-point registers */
+ add r2, r0, #(_JB_FLOAT_BASE * 4)
+ vldmia r2, {d8-d15}
+ /* Restore floating-point state */
+ ldr r2, [r0, #(_JB_FLOAT_STATE * 4)]
+ fmxr fpscr, r2
+#endif /* __ARM_HAVE_VFP */
+
+ /* Restore core registers */
+ add r2, r0, #(_JB_CORE_BASE * 4)
+ ldmia r2, {r4-r14}
/* Validate sp and r14 */
teq sp, #0
diff --git a/libc/arch-arm/include/machine/cpu-features.h b/libc/arch-arm/include/machine/cpu-features.h
index ecf6ff6..abf226a 100644
--- a/libc/arch-arm/include/machine/cpu-features.h
+++ b/libc/arch-arm/include/machine/cpu-features.h
@@ -156,6 +156,19 @@
# define _ARM_HAVE_LDREX_STREX
#endif
+/* define _ARM_HAVE_VFP if we have VFPv3
+ */
+#if __ARM_ARCH__ >= 7 && defined __VFP_FP__
+# define __ARM_HAVE_VFP
+#endif
+
+/* define _ARM_HAVE_NEON for ARMv7 architecture if we support the
+ * Neon SIMD instruction set extensions. This also implies
+ * that VFPv3-D32 is supported.
+ */
+#if __ARM_ARCH__ >= 7 && defined __ARM_NEON__
+# define __ARM_HAVE_NEON
+#endif
/* Assembly-only macros */
diff --git a/libc/arch-arm/include/machine/setjmp.h b/libc/arch-arm/include/machine/setjmp.h
index f20cab2..0941202 100644
--- a/libc/arch-arm/include/machine/setjmp.h
+++ b/libc/arch-arm/include/machine/setjmp.h
@@ -1,87 +1,82 @@
-/* $OpenBSD: setjmp.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
-/* $NetBSD: setjmp.h,v 1.2 2001/08/25 14:45:59 bjh21 Exp $ */
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
/*
* machine/setjmp.h: machine dependent setjmp-related information.
*/
-#ifdef __ELF__
-#define _JBLEN 64 /* size, in longs, of a jmp_buf */
-#else
-#define _JBLEN 29 /* size, in longs, of a jmp_buf */
-#endif
-
-/*
- * NOTE: The internal structure of a jmp_buf is *PRIVATE*
- * This information is provided as there is software
- * that fiddles with this with obtain the stack pointer
- * (yes really ! and its commercial !).
+/* _JBLEN is the size of a jmp_buf in longs.
+ * Do not modify this value or you will break the ABI !
*
- * Description of the setjmp buffer
- *
- * word 0 magic number (dependant on creator)
- * 1 - 3 f4 fp register 4
- * 4 - 6 f5 fp register 5
- * 7 - 9 f6 fp register 6
- * 10 - 12 f7 fp register 7
- * 13 fpsr fp status register
- * 14 r4 register 4
- * 15 r5 register 5
- * 16 r6 register 6
- * 17 r7 register 7
- * 18 r8 register 8
- * 19 r9 register 9
- * 20 r10 register 10 (sl)
- * 21 r11 register 11 (fp)
- * 22 r12 register 12 (ip)
- * 23 r13 register 13 (sp)
- * 24 r14 register 14 (lr)
- * 25 signal mask (dependant on magic)
- * 26 (con't)
- * 27 (con't)
- * 28 (con't)
- *
- * The magic number number identifies the jmp_buf and
- * how the buffer was created as well as providing
- * a sanity check
- *
- * A side note I should mention - Please do not tamper
- * with the floating point fields. While they are
- * always saved and restored at the moment this cannot
- * be garenteed especially if the compiler happens
- * to be generating soft-float code so no fp
- * registers will be used.
- *
- * Whilst this can be seen an encouraging people to
- * use the setjmp buffer in this way I think that it
- * is for the best then if changes occur compiles will
- * break rather than just having new builds falling over
- * mysteriously.
+ * This value comes from the original OpenBSD ARM-specific header
+ * that was replaced by this one.
*/
+#define _JBLEN 64
+
+/* According to the ARM AAPCS document, we only need to save
+ * the following registers:
+ *
+ * Core r4-r14
+ *
+ * VFP d8-d15 (see section 5.1.2.1)
+ *
+ * Registers s16-s31 (d8-d15, q4-q7) must be preserved across subroutine
+ * calls; registers s0-s15 (d0-d7, q0-q3) do not need to be preserved
+ * (and can be used for passing arguments or returning results in standard
+ * procedure-call variants). Registers d16-d31 (q8-q15), if present, do
+ * not need to be preserved.
+ *
+ * FPSCR saved because GLibc does saves it too.
+ *
+ */
+
+/* The internal structure of a jmp_buf is totally private.
+ * Current layout (may change in the future):
+ *
+ * word name description
+ * 0 magic magic number
+ * 1 sigmask signal mask (not used with _setjmp / _longjmp)
+ * 2 float_base base of float registers (d8 to d15)
+ * 18 float_state floating-point status and control register
+ * 19 core_base base of core registers (r4 to r14)
+ * 30 reserved reserved entries (room to grow)
+ * 64
+ *
+ * NOTE: float_base must be at an even word index, since the
+ * FP registers will be loaded/stored with instructions
+ * that expect 8-byte alignment.
+ */
+
+#define _JB_MAGIC 0
+#define _JB_SIGMASK (_JB_MAGIC+1)
+#define _JB_FLOAT_BASE (_JB_SIGMASK+1)
+#define _JB_FLOAT_STATE (_JB_FLOAT_BASE + (15-8+1)*2)
+#define _JB_CORE_BASE (_JB_FLOAT_STATE+1)
#define _JB_MAGIC__SETJMP 0x4278f500
#define _JB_MAGIC_SETJMP 0x4278f501
-
-/* Valid for all jmp_buf's */
-
-#define _JB_MAGIC 0
-#define _JB_REG_F4 1
-#define _JB_REG_F5 4
-#define _JB_REG_F6 7
-#define _JB_REG_F7 10
-#define _JB_REG_FPSR 13
-#define _JB_REG_R4 14
-#define _JB_REG_R5 15
-#define _JB_REG_R6 16
-#define _JB_REG_R7 17
-#define _JB_REG_R8 18
-#define _JB_REG_R9 19
-#define _JB_REG_R10 20
-#define _JB_REG_R11 21
-#define _JB_REG_R12 22
-#define _JB_REG_R13 23
-#define _JB_REG_R14 24
-
-/* Only valid with the _JB_MAGIC_SETJMP magic */
-
-#define _JB_SIGMASK 25
diff --git a/libc/docs/CHANGES.TXT b/libc/docs/CHANGES.TXT
index 9080685..6159047 100644
--- a/libc/docs/CHANGES.TXT
+++ b/libc/docs/CHANGES.TXT
@@ -3,6 +3,8 @@
Differences between current and Android 2.1:
+- Support FP register save/load in setjmp()/longjmp() on ARMv7 builds.
+
- Add support for SH-4 CPU architecture !
- __atomic_swap(): use LDREX/STREX CPU instructions on ARMv6 and higher.