From: Jeff Dike <jdike@addtoit.com>

From: Bodo Stroesser

This is the first patch of a series of four.
These patches allow the use of sysenter-systemcalls in UML
if the host support sysenter.
Some facts have to be noted:
- the sysenter instruction does not save anything, not even the
  return address. Thus the host-kernel builds a stackframe with an
  fixed return address for the backjump to the vsyscall-page. All
  kernels that support sysenter thus must have a vsyscall-page
- The hosts vsyscall-page is visible in all memory-contexts on the
  host, even in those of the processes running on UML. This cannot
  be changed.
So the best way to implement sysenter is to integrate the host's
vsyscall-page into UML, if available.

This patch creates a new source file containing an UML
initialization function. The function scans the Elf-auxiliary vector
that is prepared by the host for relevant information about:
- vsyscall elf-header
- vsyscall entry
- machine type (called "platform", e.g. "i586" or "i686")
- hardware capabilities
These informations are inserted into the Elf-auxiliary-vector that is
generated if an UML process calls "execXX()". If the information from
the auxiliray-vector is not complete, UML uses the previos default
values, with one exception: if the host has no vsyscall-page, UML now
does no longer insert AT_SYSINFO or AT_SYSINFO_EHDR elements. (I think,
that's better than writing dummies)

Since the host's vsyscall-page is always visible to UML processes, this
change is enough to let UML with an i686-compiled glibc use sysenter.

what's missing:
- is_syscall() in SKAS cannot access the code in the vsyscall-page via
  copy_from_user(), thus singlesteppers still could break out. (Note:
  that's not new, if someone jumps willingly to the sysenter-entry in
  the vsyscall-page, he can do that without the patch, too).
- a debugger cannot access the code in the vsyscall-page via
  ptrace( PEEKTEXT, ...)

Risks:
could there by any feature of the host's processor, that is indicated in
the hardware capabilities, but must not be used in UML?

Signed-off-by: Bodo Stroesser <bodo.stroesser@fujitsu-siemens.com>
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/um/kernel/main.c           |    4 +
 25-akpm/arch/um/kernel/um_arch.c        |    5 --
 25-akpm/arch/um/os-Linux/Makefile       |    5 +-
 25-akpm/arch/um/os-Linux/elf_aux.c      |   66 ++++++++++++++++++++++++++++++++
 25-akpm/include/asm-um/archparam-i386.h |   25 ++++++------
 25-akpm/include/asm-um/elf.h            |    3 -
 6 files changed, 88 insertions(+), 20 deletions(-)

diff -puN arch/um/kernel/main.c~uml-add-elf-vsyscall-support arch/um/kernel/main.c
--- 25/arch/um/kernel/main.c~uml-add-elf-vsyscall-support	Fri Dec  3 13:50:26 2004
+++ 25-akpm/arch/um/kernel/main.c	Fri Dec  3 13:50:26 2004
@@ -81,6 +81,8 @@ static void last_ditch_exit(int sig)
 
 extern int uml_exitcode;
 
+extern void scan_elf_aux( char **envp);
+
 int main(int argc, char **argv, char **envp)
 {
 	char **new_argv;
@@ -147,6 +149,8 @@ int main(int argc, char **argv, char **e
 	set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
 	set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
 
+	scan_elf_aux( envp);
+
 	do_uml_initcalls();
 	ret = linux_main(argc, argv);
 
diff -puN arch/um/kernel/um_arch.c~uml-add-elf-vsyscall-support arch/um/kernel/um_arch.c
--- 25/arch/um/kernel/um_arch.c~uml-add-elf-vsyscall-support	Fri Dec  3 13:50:26 2004
+++ 25-akpm/arch/um/kernel/um_arch.c	Fri Dec  3 13:50:26 2004
@@ -44,11 +44,6 @@ struct cpuinfo_um boot_cpu_data = { 
 	.ipi_pipe		= { -1, -1 }
 };
 
-/* Placeholder to make UML link until the vsyscall stuff is actually
- * implemented
- */
-void *__kernel_vsyscall;
-
 unsigned long thread_saved_pc(struct task_struct *task)
 {
 	return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
diff -puN arch/um/os-Linux/elf_aux.c~uml-add-elf-vsyscall-support arch/um/os-Linux/elf_aux.c
--- 25/arch/um/os-Linux/elf_aux.c~uml-add-elf-vsyscall-support	Fri Dec  3 13:50:26 2004
+++ 25-akpm/arch/um/os-Linux/elf_aux.c	Fri Dec  3 13:50:26 2004
@@ -0,0 +1,66 @@
+/*
+ *  arch/um/kernel/elf_aux.c
+ *
+ *  Scan the Elf auxiliary vector provided by the host to extract
+ *  information about vsyscall-page, etc.
+ *
+ *  Copyright (C) 2004 Fujitsu Siemens Computers GmbH
+ *  Author: Bodo Stroesser (bodo.stroesser@fujitsu-siemens.com)
+ */
+#include <elf.h>
+#include <stddef.h>
+#include "init.h"
+
+#if ELF_CLASS == ELFCLASS32
+typedef Elf32_auxv_t elf_auxv_t;
+#else
+typedef Elf64_auxv_t elf_auxv_t;
+#endif
+
+char * elf_aux_platform;
+long elf_aux_hwcap;
+
+long vsyscall_ehdr;
+long vsyscall_end;
+
+long __kernel_vsyscall;
+
+
+__init void scan_elf_aux( char **envp)
+{
+	long page_size = 0;
+	elf_auxv_t * auxv;
+
+	while ( *envp++ != NULL) ;
+
+	for ( auxv = (elf_auxv_t *)envp; auxv->a_type != AT_NULL; auxv++) {
+		switch ( auxv->a_type ) {
+			case AT_SYSINFO:
+				__kernel_vsyscall = auxv->a_un.a_val;
+				break;
+			case AT_SYSINFO_EHDR:
+				vsyscall_ehdr = auxv->a_un.a_val;
+				break;
+			case AT_HWCAP:
+				elf_aux_hwcap = auxv->a_un.a_val;
+				break;
+			case AT_PLATFORM:
+				elf_aux_platform = auxv->a_un.a_ptr;
+				break;
+			case AT_PAGESZ:
+				page_size = auxv->a_un.a_val;
+				break;
+		}
+	}
+	if ( ! __kernel_vsyscall || ! vsyscall_ehdr ||
+	     ! elf_aux_hwcap || ! elf_aux_platform ||
+	     ! page_size || (vsyscall_ehdr % page_size) ) {
+		__kernel_vsyscall = 0;
+		vsyscall_ehdr = 0;
+		elf_aux_hwcap = 0;
+		elf_aux_platform = "i586";
+	}
+	else {
+		vsyscall_end = vsyscall_ehdr + page_size;
+	}
+}
diff -puN arch/um/os-Linux/Makefile~uml-add-elf-vsyscall-support arch/um/os-Linux/Makefile
--- 25/arch/um/os-Linux/Makefile~uml-add-elf-vsyscall-support	Fri Dec  3 13:50:26 2004
+++ 25-akpm/arch/um/os-Linux/Makefile	Fri Dec  3 13:50:26 2004
@@ -3,9 +3,10 @@
 # Licensed under the GPL
 #
 
-obj-y = file.o process.o time.o tty.o user_syms.o drivers/
+obj-y = elf_aux.o file.o process.o time.o tty.o user_syms.o drivers/
 
-USER_OBJS := $(foreach file,file.o process.o time.o tty.o,$(obj)/$(file))
+USER_OBJS := elf_aux.o file.o process.o time.o tty.o
+USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
 
 $(USER_OBJS) : %.o: %.c
 	$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
diff -puN include/asm-um/archparam-i386.h~uml-add-elf-vsyscall-support include/asm-um/archparam-i386.h
--- 25/include/asm-um/archparam-i386.h~uml-add-elf-vsyscall-support	Fri Dec  3 13:50:26 2004
+++ 25-akpm/include/asm-um/archparam-i386.h	Fri Dec  3 13:50:26 2004
@@ -10,7 +10,8 @@
 
 #include "user.h"
 
-#define ELF_PLATFORM "i586"
+extern char * elf_aux_platform;
+#define ELF_PLATFORM (elf_aux_platform)
 
 #define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
 
@@ -56,15 +57,13 @@ typedef elf_greg_t elf_gregset_t[ELF_NGR
 	pr_reg[16] = PT_REGS_SS(regs);		\
 } while(0);
 
-#if 0 /* Turn this back on when UML has VSYSCALL working */
-#define VSYSCALL_BASE	(__fix_to_virt(FIX_VSYSCALL))
-#else
-#define VSYSCALL_BASE	0
-#endif
-
-#define VSYSCALL_EHDR	((const struct elfhdr *) VSYSCALL_BASE)
-#define VSYSCALL_ENTRY	((unsigned long) &__kernel_vsyscall)
-extern void *__kernel_vsyscall;
+
+extern long vsyscall_ehdr;
+extern long vsyscall_end;
+extern long __kernel_vsyscall;
+
+#define VSYSCALL_BASE vsyscall_ehdr
+#define VSYSCALL_END vsyscall_end
 
 /*
  * Architecture-neutral AT_ values in 0-17, leave some room
@@ -75,8 +74,10 @@ extern void *__kernel_vsyscall;
 
 #define ARCH_DLINFO						\
 do {								\
-		NEW_AUX_ENT(AT_SYSINFO,	VSYSCALL_ENTRY);	\
-		NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL_BASE);	\
+	if ( vsyscall_ehdr ) {					\
+		NEW_AUX_ENT(AT_SYSINFO,	__kernel_vsyscall);	\
+		NEW_AUX_ENT(AT_SYSINFO_EHDR, vsyscall_ehdr);	\
+	}							\
 } while (0)
 
 /*
diff -puN include/asm-um/elf.h~uml-add-elf-vsyscall-support include/asm-um/elf.h
--- 25/include/asm-um/elf.h~uml-add-elf-vsyscall-support	Fri Dec  3 13:50:26 2004
+++ 25-akpm/include/asm-um/elf.h	Fri Dec  3 13:50:26 2004
@@ -3,7 +3,8 @@
 
 #include "asm/archparam.h"
 
-#define ELF_HWCAP (0)
+extern long elf_aux_hwcap;
+#define ELF_HWCAP (elf_aux_hwcap)
 
 #define SET_PERSONALITY(ex, ibcs2) do ; while(0)
 
_