implement work around for tegra errata 657451
tegra 2 processors have a bug in the register read path of bit 20 of
the CP15 c13, 3 register (used for software thread local storage)
the kernel work-around for this bug is to mux the value from bit 20
into bit 0; since the TLS value used by Android is an aligned address,
bit 0 is known to be available.
diff --git a/libc/Android.mk b/libc/Android.mk
index 49c8731..59b2f0c 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -508,6 +508,9 @@
ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
libc_common_cflags += -DHAVE_ARM_TLS_REGISTER
endif
+ ifeq ($(TARGET_HAVE_TEGRA_ERRATA_657451),true)
+ libc_common_cflags += -DHAVE_TEGRA_ERRATA_657451
+ endif
else # !arm
ifeq ($(TARGET_ARCH),x86)
libc_crt_target_cflags := -m32
diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h
index 008fd2f..94a81cd 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -111,6 +111,12 @@
* Note that HAVE_ARM_TLS_REGISTER is build-specific
* (it must match your kernel configuration)
*/
+# ifdef HAVE_TEGRA_ERRATA_657451
+# define __munge_tls(_v) ( ((_v)&~((1ul<<20)|1ul)) | (((_v)&0x1)<<20) )
+# else
+# define __munge_tls(_v) (_v)
+#endif
+
# ifdef HAVE_ARM_TLS_REGISTER
/* We can read the address directly from a coprocessor
* register, which avoids touching the data cache
@@ -119,6 +125,7 @@
# define __get_tls() \
({ register unsigned int __val asm("r0"); \
asm ("mrc p15, 0, r0, c13, c0, 3" : "=r"(__val) ); \
+ __val = __munge_tls(__val); \
(volatile void*)__val; })
# else /* !HAVE_ARM_TLS_REGISTER */
/* The kernel provides the address of the TLS at a fixed
diff --git a/linker/Android.mk b/linker/Android.mk
index 9290594..bd220da 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -57,6 +57,9 @@
endif
endif
endif
+ifeq ($(TARGET_HAVE_TEGRA_ERRATA_657451),true)
+ LOCAL_CFLAGS += -DHAVE_TEGRA_ERRATA_657451
+endif
LOCAL_MODULE:= linker