All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 2/10] linux 2.6.18: COMPAT_VDSO
@ 2007-03-05 11:14 Jan Beulich
  2007-03-05 13:42 ` Keir Fraser
  2007-03-05 20:07   ` [Xen-devel] " Jeremy Fitzhardinge
  0 siblings, 2 replies; 11+ messages in thread
From: Jan Beulich @ 2007-03-05 11:14 UTC (permalink / raw)
  To: xen-devel

This adds support for CONFIG_COMPAT_VDSO. As this will certainly raise
questions, I left in the code needed for an alternative approach (which
requires mode C code, but less build script changes).

Signed-off-by: Jan Beulich <jbeulich@novell.com>

Index: head-2007-02-27/arch/i386/Kconfig
===================================================================
--- head-2007-02-27.orig/arch/i386/Kconfig	2007-03-05 10:00:18.000000000 +0100
+++ head-2007-02-27/arch/i386/Kconfig	2007-02-27 16:27:37.000000000 +0100
@@ -819,7 +819,6 @@ config HOTPLUG_CPU
 
 config COMPAT_VDSO
 	bool "Compat VDSO support"
-	depends on !X86_XEN
 	default y
 	help
 	  Map the VDSO to the predictable old-style address too.
Index: head-2007-02-27/arch/i386/kernel/Makefile
===================================================================
--- head-2007-02-27.orig/arch/i386/kernel/Makefile	2007-03-05 10:00:18.000000000 +0100
+++ head-2007-02-27/arch/i386/kernel/Makefile	2007-02-27 16:27:37.000000000 +0100
@@ -74,6 +74,52 @@ $(obj)/vsyscall-%.so: $(src)/vsyscall.ld
 		      $(obj)/vsyscall-%.o $(obj)/$(vsyscall_note) FORCE
 	$(call if_changed,syscall)
 
+ifeq ($(CONFIG_XEN)$(CONFIG_COMPAT_VDSO),yy)
+
+# vsyscall.o also contains the vsyscall DSO relocation info as __initdata.
+# We must build both alternative images before we can assemble it.
+# Note: kbuild does not track this dependency due to usage of .include
+$(obj)/vsyscall.o: $(obj)/vsyscall-int80.rel $(obj)/vsyscall-sysenter.rel
+targets += $(foreach F,int80 sysenter,vsyscall-$F.so.alt vsyscall-$F.rel)
+targets += vsyscall.lds.alt
+
+# The alternative DSO images are built using an alternate base address.
+quiet_cmd_syscall_alt = REBASE  $@
+      cmd_syscall_alt = sed 's,^\([[:space:]]*\.[[:space:]]*=[[:space:]]*\),\1-0x55AA0000 + ,' $< >$@
+
+quiet_cmd_syscall_rel = COMPARE $@
+      cmd_syscall_rel = set -e; \
+			cmp -l $(basename $<) $< \
+			| { read off1 old1 new1; \
+			    read off2 old2 new2; \
+			    test $$(expr $$off1 + 1) = $$off2; \
+			    echo " .long $$(expr $$off1 - 3)"; \
+			    while read off1 old3 new3; do \
+				read off2 old4 new4; \
+				test $$(expr $$off1 + 1) = $$off2; \
+				test $$old1 = $$old3 -a $$new1 = $$new3; \
+				test $$old2 = $$old4 -a $$new2 = $$new4; \
+				echo " .long $$(expr $$off1 - 3)"; \
+			    done; \
+			  } >$@
+
+SYSCFLAGS_vsyscall-sysenter.so.alt = $(vsyscall-flags)
+SYSCFLAGS_vsyscall-int80.so.alt    = $(vsyscall-flags)
+
+$(obj)/vsyscall.lds.alt: $(obj)/vsyscall.lds FORCE
+	$(call if_changed,syscall_alt)
+
+$(obj)/vsyscall-int80.so.alt $(obj)/vsyscall-sysenter.so.alt: \
+$(obj)/vsyscall-%.so.alt: $(obj)/vsyscall.lds.alt \
+		      $(obj)/vsyscall-%.o $(obj)/$(vsyscall_note) FORCE
+	$(call if_changed,syscall)
+
+$(obj)/vsyscall-int80.rel $(obj)/vsyscall-sysenter.rel: \
+$(obj)/vsyscall-%.rel: $(obj)/vsyscall-%.so.alt FORCE
+	$(call if_changed,syscall_rel)
+
+endif
+
 # We also create a special relocatable object that should mirror the symbol
 # table and layout of the linked DSO.  With ld -R we can then refer to
 # these symbols in the kernel code rather than hand-coded addresses.
Index: head-2007-02-27/arch/i386/kernel/sysenter.c
===================================================================
--- head-2007-02-27.orig/arch/i386/kernel/sysenter.c	2007-03-05 10:00:18.000000000 +0100
+++ head-2007-02-27/arch/i386/kernel/sysenter.c	2007-02-27 16:27:37.000000000 +0100
@@ -25,6 +25,8 @@
 
 #ifdef CONFIG_XEN
 #include <xen/interface/callback.h>
+extern const unsigned long vdso_rel_int80_start[], vdso_rel_int80_end[];
+extern const unsigned long vdso_rel_sysenter_start[], vdso_rel_sysenter_end[];
 #endif
 
 /*
@@ -66,6 +68,142 @@ void enable_sep_cpu(void)
 #endif
 }
 
+#if defined(CONFIG_XEN) && defined(CONFIG_COMPAT_VDSO)
+static void __init relocate_vdso(Elf32_Ehdr *ehdr, unsigned long old_base, unsigned long new_base,
+                                 const unsigned long *reloc_start, const unsigned long *reloc_end)
+{
+#if 1
+	const unsigned long *reloc;
+
+	for (reloc = reloc_start; reloc < reloc_end; ++reloc) {
+		unsigned long *ptr = (void *)((unsigned long)ehdr + *reloc);
+
+		*ptr += new_base - old_base;
+	}
+#else
+	unsigned i, ndynsym = 0, szdynsym = 0;
+	unsigned long dynsym = 0;
+
+	BUG_ON(ehdr->e_ident[EI_MAG0] != ELFMAG0);
+	BUG_ON(ehdr->e_ident[EI_MAG1] != ELFMAG1);
+	BUG_ON(ehdr->e_ident[EI_MAG2] != ELFMAG2);
+	BUG_ON(ehdr->e_ident[EI_MAG3] != ELFMAG3);
+	BUG_ON(ehdr->e_ident[EI_CLASS] != ELFCLASS32);
+	BUG_ON(ehdr->e_ident[EI_DATA] != ELFDATA2LSB);
+	BUG_ON(ehdr->e_ehsize < sizeof(*ehdr));
+	ehdr->e_entry += new_base - old_base;
+	BUG_ON(ehdr->e_phentsize < sizeof(Elf32_Phdr));
+	for (i = 0; i < ehdr->e_phnum; ++i) {
+		Elf32_Phdr *phdr = (void *)((unsigned long)ehdr + ehdr->e_phoff + i * ehdr->e_phentsize);
+
+		phdr->p_vaddr += new_base - old_base;
+		switch(phdr->p_type) {
+		case PT_LOAD:
+		case PT_NOTE:
+			break;
+		case PT_DYNAMIC: {
+				Elf32_Dyn *dyn = (void *)(phdr->p_vaddr - new_base + (unsigned long)ehdr);
+				unsigned j;
+
+				for(j = 0; dyn[j].d_tag != DT_NULL; ++j) {
+					switch(dyn[j].d_tag) {
+					case DT_HASH:
+					case DT_STRTAB:
+					case DT_SYMTAB:
+					case 0x6ffffff0: /* DT_VERSYM */
+					case 0x6ffffffc: /* DT_VERDEF */
+						break;
+					case DT_SONAME:
+					case DT_STRSZ:
+					case 0x6ffffffd: /* DT_VERDEFNUM */
+						continue;
+					case DT_SYMENT:
+						szdynsym = dyn[j].d_un.d_val;
+						continue;
+					default:
+						if (dyn[j].d_tag >= 0x60000000 /* OLD_DT_LOOS */
+						    || dyn[j].d_tag < 31 /* DT_ENCODING */
+						    || !(dyn[j].d_tag & 1)) {
+							printk(KERN_WARNING "vDSO dynamic info %u has unsupported tag
%08X\n", j, dyn[j].d_tag);
+							WARN_ON(1);
+							continue;
+						}
+						break;
+					}
+					dyn[j].d_un.d_ptr += new_base - old_base;
+					switch(dyn[j].d_tag) {
+					case DT_HASH:
+						ndynsym = ((Elf32_Word *)dyn[j].d_un.d_ptr)[1];
+						break;
+					case DT_SYMTAB:
+						dynsym = dyn[j].d_un.d_ptr;
+						break;
+					}
+				}
+			}
+			break;
+		case PT_GNU_EH_FRAME:
+			/* XXX */
+			break;
+		default:
+			printk(KERN_WARNING "vDSO program header %u has unsupported type %08X\n", i, phdr->p_type);
+			WARN_ON(1);
+			break;
+		}
+	}
+	BUG_ON(ehdr->e_shentsize < sizeof(Elf32_Shdr));
+	BUG_ON(ehdr->e_shnum >= SHN_LORESERVE);
+	for (i = 1; i < ehdr->e_shnum; ++i) {
+		Elf32_Shdr *shdr = (void *)((unsigned long)ehdr + ehdr->e_shoff + i * ehdr->e_shentsize);
+
+		if (!(shdr->sh_flags & SHF_ALLOC))
+			continue;
+		shdr->sh_addr += new_base - old_base;
+		switch(shdr->sh_type) {
+		case SHT_DYNAMIC:
+		case SHT_HASH:
+		case SHT_NOBITS:
+		case SHT_NOTE:
+		case SHT_PROGBITS:
+		case SHT_STRTAB:
+		case 0x6ffffffd: /* SHT_GNU_verdef */
+		case 0x6fffffff: /* SHT_GNU_versym */
+			break;
+		case SHT_DYNSYM:
+			BUG_ON(shdr->sh_entsize < sizeof(Elf32_Sym));
+			if (!szdynsym)
+				szdynsym = shdr->sh_entsize;
+			else
+				WARN_ON(szdynsym != shdr->sh_entsize);
+			if (!ndynsym)
+				ndynsym = shdr->sh_size / szdynsym;
+			else
+				WARN_ON(ndynsym != shdr->sh_size / szdynsym);
+			if (!dynsym)
+				dynsym = shdr->sh_addr;
+			else
+				WARN_ON(dynsym != shdr->sh_addr);
+			break;
+		default:
+			printk(KERN_WARNING "vDSO section %u has unsupported type %08X\n", i, shdr->sh_type);
+			WARN_ON(shdr->sh_size);
+			break;
+		}
+	}
+	dynsym += (unsigned long)ehdr - new_base;
+	for(i = 1; i < ndynsym; ++i) {
+		Elf32_Sym *sym = (void *)(dynsym + i * szdynsym);
+
+		if (sym->st_shndx == SHN_ABS)
+			continue;
+		sym->st_value += new_base - old_base;
+	}
+#endif
+}
+#else
+#define relocate_vdso(ehdr, old, new, start, end) ((void)0)
+#endif
+
 /*
  * These symbols are defined by vsyscall.o to mark the bounds
  * of the ELF DSO images included therein.
@@ -104,12 +245,16 @@ int __init sysenter_setup(void)
 		memcpy(syscall_page,
 		       &vsyscall_int80_start,
 		       &vsyscall_int80_end - &vsyscall_int80_start);
+		relocate_vdso(syscall_page, VDSO_PRELINK, __fix_to_virt(FIX_VDSO),
+		              vdso_rel_int80_start, vdso_rel_int80_end);
 		return 0;
 	}
 
 	memcpy(syscall_page,
 	       &vsyscall_sysenter_start,
 	       &vsyscall_sysenter_end - &vsyscall_sysenter_start);
+	relocate_vdso(syscall_page, VDSO_PRELINK, __fix_to_virt(FIX_VDSO),
+	              vdso_rel_sysenter_start, vdso_rel_sysenter_end);
 
 	return 0;
 }
Index: head-2007-02-27/arch/i386/kernel/vsyscall.S
===================================================================
--- head-2007-02-27.orig/arch/i386/kernel/vsyscall.S	2007-03-05 10:00:18.000000000 +0100
+++ head-2007-02-27/arch/i386/kernel/vsyscall.S	2007-02-27 16:27:37.000000000 +0100
@@ -12,4 +12,20 @@ vsyscall_sysenter_start:
 	.incbin "arch/i386/kernel/vsyscall-sysenter.so"
 vsyscall_sysenter_end:
 
+#if defined(CONFIG_XEN) && defined(CONFIG_COMPAT_VDSO)
+
+	.align 4
+
+	.globl vdso_rel_int80_start, vdso_rel_int80_end
+vdso_rel_int80_start:
+	.include "arch/i386/kernel/vsyscall-int80.rel"
+vdso_rel_int80_end:
+
+	.globl vdso_rel_sysenter_start, vdso_rel_sysenter_end
+vdso_rel_sysenter_start:
+	.include "arch/i386/kernel/vsyscall-sysenter.rel"
+vdso_rel_sysenter_end:
+
+#endif
+
 __FINIT
Index: head-2007-02-27/include/asm-i386/elf.h
===================================================================
--- head-2007-02-27.orig/include/asm-i386/elf.h	2007-03-05 10:00:18.000000000 +0100
+++ head-2007-02-27/include/asm-i386/elf.h	2007-02-27 16:27:37.000000000 +0100
@@ -137,7 +137,11 @@ extern int dump_task_extended_fpu (struc
 
 #ifdef CONFIG_COMPAT_VDSO
 # define VDSO_COMPAT_BASE	VDSO_HIGH_BASE
-# define VDSO_PRELINK		VDSO_HIGH_BASE
+# ifndef CONFIG_XEN
+#  define VDSO_PRELINK		VDSO_HIGH_BASE
+# else
+#  define VDSO_PRELINK		(0UL - FIX_VDSO * PAGE_SIZE)
+# endif
 #else
 # define VDSO_COMPAT_BASE	VDSO_BASE
 # define VDSO_PRELINK		0

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2007-03-09 14:59 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-03-05 11:14 [PATCH 2/10] linux 2.6.18: COMPAT_VDSO Jan Beulich
2007-03-05 13:42 ` Keir Fraser
2007-03-05 14:48   ` Jan Beulich
2007-03-05 15:55     ` Keir Fraser
2007-03-09 10:17       ` Jan Beulich
2007-03-09 10:39         ` Keir Fraser
2007-03-09 14:59         ` Jeremy Fitzhardinge
2007-03-05 20:07 ` Jeremy Fitzhardinge
2007-03-05 20:07   ` [Xen-devel] " Jeremy Fitzhardinge
2007-03-06  7:52   ` Jan Beulich
2007-03-06  7:52     ` Jan Beulich

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.