[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 2/10] linux 2.6.18: COMPAT_VDSO



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@xxxxxxxxxx>

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



_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.