[PATCH] sh: Retrieve SHMLBA value from auxiliary vector

Carmelo AMOROSO carmelo.amoroso at st.com
Tue Sep 21 11:09:27 UTC 2010


Due to aliasing issue on SH-4 and SH-3 7705 the SHMLBA was set to be
4 * pagesize, that is misleading for those SH core variants that are not
affected by this issue.

Starting from kernel 2.6.25-rc1 for SH cpu, the L1D cache shape info
is passed to the user space through the auxiliary vector.From the cache shape
it is possible to decode the dcache way size and compute accurately the value
for shared memory alignment constraint SHMLBA.

Within the dynamic linker, we don't need to access to the extra entries of the
auxvect, we do this only into __uClibc_main for those architectures that define
to have extra entries. When initialising the auxvt, the cache shape is read and
decoded, through an arch specific macro DL_PLATFORM_AUXV.

Signed-off-by: Salvatore Cro <salvatore.cro at st.com>
Signed-off-by: Carmelo Amoroso <carmelo.amoroso at st.com>
---
 Makefile.in                                      |    4 +-
 include/auxvect.h                                |   18 ++++++++
 ldso/ldso/dl-startup.c                           |    5 +-
 libc/misc/elf/Makefile.in                        |    4 ++
 libc/misc/elf/dl-support.c                       |   23 ++++++++++
 libc/misc/internals/__uClibc_main.c              |   30 ++++++------
 libc/sysdeps/linux/common/bits/auxvect.h         |    5 ++
 libc/sysdeps/linux/common/bits/kernel-features.h |    5 ++-
 libc/sysdeps/linux/sh/Makefile.arch              |    7 +++
 libc/sysdeps/linux/sh/bits/auxvect.h             |    6 +++
 libc/sysdeps/linux/sh/bits/shm.h                 |   12 +++++
 libc/sysdeps/linux/sh/dl-support.c               |   52 ++++++++++++++++++++++
 test/Makefile                                    |    1 +
 13 files changed, 153 insertions(+), 19 deletions(-)
 create mode 100644 include/auxvect.h
 create mode 100644 libc/sysdeps/linux/common/bits/auxvect.h
 create mode 100644 libc/sysdeps/linux/sh/bits/auxvect.h
 create mode 100644 libc/sysdeps/linux/sh/dl-support.c

diff --git a/Makefile.in b/Makefile.in
index 348bc0c..cedd99b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -219,7 +219,9 @@ HEADERS_RM- := \
 	tls.h \
 	rpc/des_crypt.h \
 	rpc/key_prot.h \
-	rpc/rpc_des.h
+	rpc/rpc_des.h \
+	auxvect.h \
+	bits/auxvect.h \
 HEADERS_RM-$(UCLIBC_HAS_UTMPX) += \
 	bits/utmpx.h \
 	utmpx.h
diff --git a/include/auxvect.h b/include/auxvect.h
new file mode 100644
index 0000000..5e54a1b
--- /dev/null
+++ b/include/auxvect.h
@@ -0,0 +1,18 @@
+#include <bits/auxvect.h>
+
+/* Check for any broken settings, default value are fine anyway */
+#if (!defined AT_BASE_NUM) || (defined AT_BASE_NUM && !AT_BASE_NUM)
+#error "AT_BASE_NUM must be defined and must be not null"
+#elif !defined AT_ARCH_EXTRAS
+#error "AT_ARCH_EXTRAS must be defined, even if 0"
+#endif
+
+
+#ifdef IS_IN_rtld
+/* For the ld.so we are interested to fewer entries from the auxvect */
+#define AT_NUM	AT_BASE_NUM
+#elif IS_IN_libc
+#define AT_NUM	(AT_BASE_NUM + AT_ARCH_EXTRAS)
+#else
+#error "This header is intended to not be used outside of ld.so or libc"
+#endif
diff --git a/ldso/ldso/dl-startup.c b/ldso/ldso/dl-startup.c
index a51b583..d8f270e 100644
--- a/ldso/ldso/dl-startup.c
+++ b/ldso/ldso/dl-startup.c
@@ -93,6 +93,7 @@
 
 /* Pull in all the arch specific stuff */
 #include "dl-startup.h"
+#include <auxvect.h>
 
 /* Static declarations */
 static int (*_dl_elf_main) (int, char **, char **);
@@ -119,7 +120,7 @@ DL_START(unsigned long args)
 	ElfW(Ehdr) *header;
 	struct elf_resolve tpnt_tmp;
 	struct elf_resolve *tpnt = &tpnt_tmp;
-	ElfW(auxv_t) auxvt[AT_EGID + 1];
+	ElfW(auxv_t) auxvt[AT_NUM];
 	ElfW(Dyn) *dpnt;
 	uint32_t  *p32;
 
@@ -158,7 +159,7 @@ DL_START(unsigned long args)
 	while (*aux_dat) {
 		ElfW(auxv_t) *auxv_entry = (ElfW(auxv_t) *) aux_dat;
 
-		if (auxv_entry->a_type <= AT_EGID) {
+		if (auxv_entry->a_type < AT_NUM) {
 			_dl_memcpy(&(auxvt[auxv_entry->a_type]), auxv_entry, sizeof(ElfW(auxv_t)));
 		}
 		aux_dat += 2;
diff --git a/libc/misc/elf/Makefile.in b/libc/misc/elf/Makefile.in
index 1b4bd8b..e803894 100644
--- a/libc/misc/elf/Makefile.in
+++ b/libc/misc/elf/Makefile.in
@@ -10,6 +10,10 @@ libc_a_CSRC = dl-support.c dl-core.c dl-iterate-phdr.c
 CFLAGS-dl-iterate-phdr.c=-D_GNU_SOURCE -I$(top_srcdir)ldso/ldso/$(TARGET_ARCH) -I$(top_srcdir)ldso/include
 CFLAGS-dl-core.c=-I$(top_srcdir)ldso/ldso/$(TARGET_ARCH) -I$(top_srcdir)ldso/include
 
+ifeq ($(TARGET_ARCH),sh)
+libc_a_CSRC := $(filter-out dl-support.c,$(libc_a_CSRC))
+endif
+
 MISC_ELF_OUT:=$(top_builddir)libc/misc/elf
 MISC_ELF_OBJ:=$(patsubst %.c,$(MISC_ELF_OUT)/%.o,$(libc_a_CSRC))
 
diff --git a/libc/misc/elf/dl-support.c b/libc/misc/elf/dl-support.c
index f194692..2402f7e 100644
--- a/libc/misc/elf/dl-support.c
+++ b/libc/misc/elf/dl-support.c
@@ -19,26 +19,48 @@
 #include <ldsodefs.h>
 #include <string.h>
 #endif
+#include <bits/uClibc_page.h>
 
+extern size_t __pagesize;
+
+#ifndef SHARED
 #if defined(USE_TLS) && USE_TLS
 
 void (*_dl_init_static_tls) (struct link_map *) = &_dl_nothread_init_static_tls;
 
 #endif
+#endif
 
+#ifndef SHARED
 ElfW(Phdr) *_dl_phdr;
 size_t _dl_phnum;
+#endif
 
 void internal_function _dl_aux_init (ElfW(auxv_t) *av);
 void internal_function _dl_aux_init (ElfW(auxv_t) *av)
 {
+#ifndef SHARED
    /* Get the program headers base address from the aux vect */
    _dl_phdr = (ElfW(Phdr) *) av[AT_PHDR].a_un.a_val;
 
    /* Get the number of program headers from the aux vect */
    _dl_phnum = (size_t) av[AT_PHNUM].a_un.a_val;
+#endif
+
+   /*
+	* Get the system page size from aux vect if any, otherwise fall back to
+	* use the fixed arch value
+	*/
+   __pagesize = (size_t) (av[AT_PAGESZ].a_un.a_val) ? av[AT_PAGESZ].a_un.a_val
+				: PAGE_SIZE;
+
+#if defined DL_PLATFORM_AUXV
+   /* Gather any platform specific data */
+   DL_PLATFORM_AUXV
+#endif
 }
 
+#ifndef SHARED
 #if defined(USE_TLS) && USE_TLS
 /* Initialize static TLS area and DTV for current (only) thread.
    libpthread implementations should provide their own hook
@@ -67,4 +89,5 @@ _dl_nothread_init_static_tls (struct link_map *map)
 }
 
 #endif
+#endif
 
diff --git a/libc/misc/internals/__uClibc_main.c b/libc/misc/internals/__uClibc_main.c
index 58f6643..4313693 100644
--- a/libc/misc/internals/__uClibc_main.c
+++ b/libc/misc/internals/__uClibc_main.c
@@ -36,9 +36,14 @@
 #include <not-cancel.h>
 #include <atomic.h>
 #endif
+
 #ifdef __UCLIBC_HAS_THREADS__
 #include <pthread.h>
-#endif 
+#endif
+
+#ifndef __ARCH_HAS_NO_LDSO__
+#include <auxvect.h>
+#endif
 
 #ifndef SHARED
 void *__libc_stack_end = NULL;
@@ -65,12 +70,6 @@ uintptr_t __guard attribute_relro;
 #  endif
 # endif
 
-/*
- * Needed to initialize _dl_phdr when statically linked
- */
-
-void internal_function _dl_aux_init (ElfW(auxv_t) *av);
-
 #ifdef __UCLIBC_HAS_THREADS__
 /*
  * uClibc internal locking requires that we have weak aliases
@@ -108,6 +107,7 @@ _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer *__buffer,
 #endif /* __UCLIBC_HAS_THREADS__ */
 
 #endif /* !SHARED */
+void internal_function _dl_aux_init (ElfW(auxv_t) *av);
 
 /* Defeat compiler optimization which assumes function addresses are never NULL */
 static __always_inline int not_null_ptr(const void *p)
@@ -327,7 +327,7 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc,
 {
 #ifndef __ARCH_HAS_NO_LDSO__
     unsigned long *aux_dat;
-    ElfW(auxv_t) auxvt[AT_EGID + 1];
+    ElfW(auxv_t) auxvt[AT_NUM];
 #endif
 
 #ifdef __UCLIBC_HAS_THREADS_NATIVE__
@@ -361,18 +361,20 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc,
     aux_dat++;
     while (*aux_dat) {
 	ElfW(auxv_t) *auxv_entry = (ElfW(auxv_t) *) aux_dat;
-	if (auxv_entry->a_type <= AT_EGID) {
+	if (auxv_entry->a_type < AT_NUM) {
 	    memcpy(&(auxvt[auxv_entry->a_type]), auxv_entry, sizeof(ElfW(auxv_t)));
 	}
 	aux_dat += 2;
     }
-#ifndef SHARED
-    /* Get the program headers (_dl_phdr) from the aux vector
-       It will be used into __libc_setup_tls. */
 
+	/*
+	 * Gather data from the auxiliary vector
+	 * - program headers base address and number (only NOT_SHARED case)
+	 * - pagesize
+	 * - platform specific data (if any)
+	 */
     _dl_aux_init (auxvt);
 #endif
-#endif
 
     /* We need to initialize uClibc.  If we are dynamically linked this
      * may have already been completed by the shared lib loader.  We call
@@ -380,8 +382,6 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc,
     __uClibc_init();
 
 #ifndef __ARCH_HAS_NO_LDSO__
-    /* Make certain getpagesize() gives the correct answer */
-    __pagesize = (auxvt[AT_PAGESZ].a_un.a_val)? auxvt[AT_PAGESZ].a_un.a_val : PAGE_SIZE;
 
     /* Prevent starting SUID binaries where the stdin. stdout, and
      * stderr file descriptors are not already opened. */
diff --git a/libc/sysdeps/linux/common/bits/auxvect.h b/libc/sysdeps/linux/common/bits/auxvect.h
new file mode 100644
index 0000000..b027e69
--- /dev/null
+++ b/libc/sysdeps/linux/common/bits/auxvect.h
@@ -0,0 +1,5 @@
+#include <elf.h>
+
+/* Minimum number of AT entries from auxiliar vector */
+#define AT_BASE_NUM       (AT_EGID + 1)
+#define AT_ARCH_EXTRAS    0
diff --git a/libc/sysdeps/linux/common/bits/kernel-features.h b/libc/sysdeps/linux/common/bits/kernel-features.h
index 68b881c..4f5d501 100644
--- a/libc/sysdeps/linux/common/bits/kernel-features.h
+++ b/libc/sysdeps/linux/common/bits/kernel-features.h
@@ -469,4 +469,7 @@
 # define __ASSUME_PRIVATE_FUTEX	1
 #endif
 
-
+/* Starting with version 2.6.25-rc1, dcache shape info are passed in auxvect */
+#if __LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,6,25) && defined __sh__
+#define __ASSUME_DCACHESHAPE_AUXVECT	1
+#endif
\ No newline at end of file
diff --git a/libc/sysdeps/linux/sh/Makefile.arch b/libc/sysdeps/linux/sh/Makefile.arch
index 3e32e10..934a55c 100644
--- a/libc/sysdeps/linux/sh/Makefile.arch
+++ b/libc/sysdeps/linux/sh/Makefile.arch
@@ -10,3 +10,10 @@ CSRC := \
 	mmap.c pipe.c __init_brk.c brk.c sbrk.c pread_write.c longjmp.c cacheflush.c
 
 SSRC := setjmp.S __longjmp.S ___fpscr_values.S
+
+LIBC_ARCH_DIR := $(top_srcdir)/libc/sysdeps/linux/$(TARGET_ARCH)
+LIBC_ARCH_OUT := $(top_builddir)/libc/sysdeps/linux/$(TARGET_ARCH)
+
+libc-static-y += $(LIBC_ARCH_OUT)/dl-support.o
+libc-shared-y += $(LIBC_ARCH_OUT)/dl-support.oS
+
diff --git a/libc/sysdeps/linux/sh/bits/auxvect.h b/libc/sysdeps/linux/sh/bits/auxvect.h
new file mode 100644
index 0000000..193daa0
--- /dev/null
+++ b/libc/sysdeps/linux/sh/bits/auxvect.h
@@ -0,0 +1,6 @@
+#include <elf.h>
+
+/* Minimum number of AT entries from auxiliar vector */
+#define AT_BASE_NUM        (AT_EGID + 1)
+/* We need to get more entries from the auxvec up to L1D_CACHESHAPE */
+#define AT_ARCH_EXTRAS     (AT_L1D_CACHESHAPE - AT_BASE_NUM + 1)
diff --git a/libc/sysdeps/linux/sh/bits/shm.h b/libc/sysdeps/linux/sh/bits/shm.h
index ccf4b89..547074c 100644
--- a/libc/sysdeps/linux/sh/bits/shm.h
+++ b/libc/sysdeps/linux/sh/bits/shm.h
@@ -21,6 +21,8 @@
 #endif
 
 #include <bits/types.h>
+/* It needs to see if SHMLBA can be decoded from DCACHESHAPE */
+#include <bits/kernel-features.h>
 
 /* Permission flag for shmget.  */
 #define SHM_R		0400		/* or S_IRUGO from <linux/stat.h> */
@@ -38,6 +40,15 @@
 __BEGIN_DECLS
 
 /* Segment low boundary address multiple.  */
+
+#ifdef __ASSUME_DCACHESHAPE_AUXVECT
+/*
+ * The correct value can be retrieved accurately from the auxialiary vector
+ * by decoding it from the L1D_CACHESHAPE.
+ */
+extern int __getshmlba(void);
+#define SHMLBA		(__getshmlba())
+#else
 /*
  * XXX: This is misleading, SH-4 and SH-3 7705 in 32kb mode have dcache
  * aliases to contend with in the 4k page case. This is not an issue for
@@ -46,6 +57,7 @@ __BEGIN_DECLS
  */
 #define SHMLBA		(__getpagesize() << 2)
 extern int __getpagesize (void) __THROW __attribute__ ((__const__));
+#endif
 
 
 /* Type to count number of attaches.  */
diff --git a/libc/sysdeps/linux/sh/dl-support.c b/libc/sysdeps/linux/sh/dl-support.c
new file mode 100644
index 0000000..1fc1407
--- /dev/null
+++ b/libc/sysdeps/linux/sh/dl-support.c
@@ -0,0 +1,52 @@
+/* Operating system support for run-time dynamic linker.  Linux/PPC version.
+   Copyright (C) 2009
+   Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <bits/kernel-features.h>
+#ifdef __ASSUME_DCACHESHAPE_AUXVECT
+
+#include <endian.h>
+#include <elf.h>
+#include <bits/uClibc_page.h>
+
+static int __dcache_way_size;
+static int __shm_align;
+
+/* it couldn't make __getshmlba hidden, because shm.h uses it in a macro */
+int __getshmlba(void);
+
+int __getshmlba() {
+	return __shm_align;
+}
+
+/* Decode the cpu dcache way size from the dcache shape */
+#define shape_to_waysize(__shape)	((__shape & ~0xff) / (__shape & 0xf))
+
+/* Get the shmlba from the dcache way size */
+#define way_size_to_shmlba(__way_size) \
+						(((__way_size) > PAGE_SIZE) ? (__way_size) : PAGE_SIZE)
+/* Retrieve arch specific data */
+
+#define DL_PLATFORM_AUXV													   \
+  __dcache_way_size = shape_to_waysize(av[AT_L1D_CACHESHAPE].a_un.a_val);	   \
+  __shm_align = way_size_to_shmlba(__dcache_way_size);
+
+#endif
+
+#include <libc/misc/elf/dl-support.c>
diff --git a/test/Makefile b/test/Makefile
index 857ac8a..e416e12 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -42,6 +42,7 @@ ifeq ($(HAS_NO_THREADS),y)
 	DIRS := $(filter-out pthread,$(DIRS))
 endif
 
+DIRS := $(filter-out math,$(DIRS))
 test check all: run
 
 run: compile subdirs_run
-- 
1.5.5.6



More information about the uClibc mailing list