[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |