sh4: position stack as real hardware and update auxv entries

This patch makes the sh4 user space emulator for linux behave like
the linux environment on my target device. The main part of the patch
reorders and updates the auxv entries to match the target kernel. A small
but important change is the hardcoded stack placement. The value used is
identical to the sh4 target placement and it happens to work well on i386
hosts. The host and target kernels probably need tuning for this to work
properly - disable vma randomization in /proc/sys/kernel/randomize_va_space
The sh4 target may need disabled vdso as well in /proc/sys/vm/vdso_enabled

Signed-off-by: Magnus Damm <damm@igel.co.jp>

--- 0001/elf.h
+++ work/elf.h	2007-06-07 12:00:43.000000000 +0900
@@ -204,6 +204,7 @@ typedef int64_t  Elf64_Sxword;
 #define AT_PLATFORM 15  /* string identifying CPU for optimizations */
 #define AT_HWCAP  16    /* arch dependent hints at CPU capabilities */
 #define AT_CLKTCK 17	/* frequency at which times() increments */
+#define AT_SECURE 23    /* secure mode boolean */
 
 typedef struct dynamic{
   Elf32_Sword d_tag;
--- 0008/linux-user/elfload.c
+++ work/linux-user/elfload.c	2007-06-07 15:25:34.000000000 +0900
@@ -331,6 +331,9 @@ static inline void init_thread(struct ta
 #define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE        4096
 
+#define ELF_HWCAP 0x21
+#define ELF_CLKTCK 0x64
+
 #endif
 
 #ifdef TARGET_M68K
@@ -391,6 +394,10 @@ static inline void init_thread(struct ta
 #define ELF_HWCAP 0
 #endif
 
+#ifndef ELF_CLKTCK
+#define ELF_CLKTCK 0
+#endif
+
 #include "elf.h"
 
 struct exec
@@ -446,7 +453,7 @@ struct exec
 #define INTERPRETER_AOUT 1
 #define INTERPRETER_ELF 2
 
-#define DLINFO_ITEMS 12
+#define DLINFO_ITEMS 13
 
 static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
 {
@@ -577,7 +584,11 @@ unsigned long setup_arg_pages(target_ulo
     size = x86_stack_size;
     if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
         size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
+#ifdef TARGET_SH4 /* sh4: use same base address as real kernel */
+    error = target_mmap(0x7c000000 - size,
+#else
     error = target_mmap(0, 
+#endif
                         size + qemu_host_page_size,
                         PROT_READ | PROT_WRITE,
                         MAP_PRIVATE | MAP_ANONYMOUS,
@@ -700,23 +711,7 @@ static unsigned long create_elf_tables(t
             sp -= n; tputl(sp, val); \
             sp -= n; tputl(sp, id); \
           } while(0)
-        NEW_AUX_ENT (AT_NULL, 0);
 
-        /* There must be exactly DLINFO_ITEMS entries here.  */
-        NEW_AUX_ENT(AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
-        NEW_AUX_ENT(AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
-        NEW_AUX_ENT(AT_PHNUM, (target_ulong)(exec->e_phnum));
-        NEW_AUX_ENT(AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
-        NEW_AUX_ENT(AT_BASE, (target_ulong)(interp_load_addr));
-        NEW_AUX_ENT(AT_FLAGS, (target_ulong)0);
-        NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
-        NEW_AUX_ENT(AT_UID, (target_ulong) getuid());
-        NEW_AUX_ENT(AT_EUID, (target_ulong) geteuid());
-        NEW_AUX_ENT(AT_GID, (target_ulong) getgid());
-        NEW_AUX_ENT(AT_EGID, (target_ulong) getegid());
-        NEW_AUX_ENT(AT_HWCAP, (target_ulong) ELF_HWCAP);
-        if (k_platform)
-            NEW_AUX_ENT(AT_PLATFORM, u_platform);
 #ifdef ARCH_DLINFO
 	/* 
 	 * ARCH_DLINFO must come last so platform specific code can enforce
@@ -724,6 +719,26 @@ static unsigned long create_elf_tables(t
 	 */
         ARCH_DLINFO;
 #endif
+
+        /* There must be exactly DLINFO_ITEMS entries here.  */
+
+        if (k_platform)
+            NEW_AUX_ENT(AT_PLATFORM, u_platform);
+        NEW_AUX_ENT(AT_SECURE, (target_ulong) 0);
+        NEW_AUX_ENT(AT_EGID, (target_ulong) 0 /* getegid() */);
+        NEW_AUX_ENT(AT_GID, (target_ulong) 0 /* getgid() */);
+        NEW_AUX_ENT(AT_EUID, (target_ulong) 0 /* geteuid() */);
+        NEW_AUX_ENT(AT_UID, (target_ulong) 0/* getuid() */);
+        NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
+        NEW_AUX_ENT(AT_FLAGS, (target_ulong)0);
+        NEW_AUX_ENT(AT_BASE, (target_ulong)(interp_load_addr));
+        NEW_AUX_ENT(AT_PHNUM, (target_ulong)(exec->e_phnum));
+        NEW_AUX_ENT(AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
+        NEW_AUX_ENT(AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
+        NEW_AUX_ENT(AT_CLKTCK, (target_ulong) ELF_CLKTCK);
+        NEW_AUX_ENT(AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
+        NEW_AUX_ENT(AT_HWCAP, (target_ulong) ELF_HWCAP);
+
 #undef NEW_AUX_ENT
 
         sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
