powerpc/8xx: Use SPRG2 and DAR registers to stash r11 and cr.
[safe/jmp/linux-2.6] / arch / powerpc / kernel / vdso.c
index e619d42..d84d192 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  *    Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp.
  *                      <benh@kernel.crashing.org>
@@ -49,6 +50,9 @@
 /* Max supported size for symbol names */
 #define MAX_SYMNAME    64
 
+/* The alignment of the vDSO */
+#define VDSO_ALIGNMENT (1 << 16)
+
 extern char vdso32_start, vdso32_end;
 static void *vdso32_kbase = &vdso32_start;
 static unsigned int vdso32_pages;
@@ -74,7 +78,7 @@ static int vdso_ready;
 static union {
        struct vdso_data        data;
        u8                      page[PAGE_SIZE];
-} vdso_data_store __attribute__((__section__(".data.page_aligned")));
+} vdso_data_store __page_aligned_data;
 struct vdso_data *vdso_data = &vdso_data_store.data;
 
 /* Format of the patch table */
@@ -184,8 +188,7 @@ static void dump_vdso_pages(struct vm_area_struct * vma)
  * This is called from binfmt_elf, we create the special vma for the
  * vDSO and insert it into the mm struct tree
  */
-int arch_setup_additional_pages(struct linux_binprm *bprm,
-                               int executable_stack)
+int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 {
        struct mm_struct *mm = current->mm;
        struct page **vdso_pagelist;
@@ -204,7 +207,12 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
        } else {
                vdso_pagelist = vdso64_pagelist;
                vdso_pages = vdso64_pages;
-               vdso_base = VDSO64_MBASE;
+               /*
+                * On 64bit we don't have a preferred map address. This
+                * allows get_unmapped_area to find an area near other mmaps
+                * and most likely share a SLB entry.
+                */
+               vdso_base = 0;
        }
 #else
        vdso_pagelist = vdso32_pagelist;
@@ -226,15 +234,28 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
         * pick a base address for the vDSO in process space. We try to put it
         * at vdso_base which is the "natural" base for it, but we might fail
         * and end up putting it elsewhere.
+        * Add enough to the size so that the result can be aligned.
         */
        down_write(&mm->mmap_sem);
        vdso_base = get_unmapped_area(NULL, vdso_base,
-                                     vdso_pages << PAGE_SHIFT, 0, 0);
+                                     (vdso_pages << PAGE_SHIFT) +
+                                     ((VDSO_ALIGNMENT - 1) & PAGE_MASK),
+                                     0, 0);
        if (IS_ERR_VALUE(vdso_base)) {
                rc = vdso_base;
                goto fail_mmapsem;
        }
 
+       /* Add required alignment. */
+       vdso_base = ALIGN(vdso_base, VDSO_ALIGNMENT);
+
+       /*
+        * Put vDSO base into mm struct. We need to do this before calling
+        * install_special_mapping or the perf counter mmap tracking code
+        * will fail to recognise it as a vDSO (since arch_vma_name fails).
+        */
+       current->mm->context.vdso_base = vdso_base;
+
        /*
         * our vma flags don't have VM_WRITE so by default, the process isn't
         * allowed to write those pages.
@@ -255,11 +276,10 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
                                     VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
                                     VM_ALWAYSDUMP,
                                     vdso_pagelist);
-       if (rc)
+       if (rc) {
+               current->mm->context.vdso_base = 0;
                goto fail_mmapsem;
-
-       /* Put vDSO base into mm struct */
-       current->mm->context.vdso_base = vdso_base;
+       }
 
        up_write(&mm->mmap_sem);
        return 0;
@@ -701,7 +721,7 @@ static int __init vdso_init(void)
 
 #ifdef CONFIG_PPC64
        /*
-        * Fill up the "systemcfg" stuff for backward compatiblity
+        * Fill up the "systemcfg" stuff for backward compatibility
         */
        strcpy((char *)vdso_data->eye_catcher, "SYSTEMCFG:PPC64");
        vdso_data->version.major = SYSTEMCFG_MAJOR;