linux/arch/powerpc/kernel/vdso.c
<<
>>
Prefs
   1/*
   2 *    Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp.
   3 *                       <benh@kernel.crashing.org>
   4 *
   5 *  This program is free software; you can redistribute it and/or
   6 *  modify it under the terms of the GNU General Public License
   7 *  as published by the Free Software Foundation; either version
   8 *  2 of the License, or (at your option) any later version.
   9 */
  10
  11#include <linux/module.h>
  12#include <linux/errno.h>
  13#include <linux/sched.h>
  14#include <linux/kernel.h>
  15#include <linux/mm.h>
  16#include <linux/smp.h>
  17#include <linux/stddef.h>
  18#include <linux/unistd.h>
  19#include <linux/slab.h>
  20#include <linux/user.h>
  21#include <linux/elf.h>
  22#include <linux/security.h>
  23#include <linux/bootmem.h>
  24#include <linux/lmb.h>
  25
  26#include <asm/pgtable.h>
  27#include <asm/system.h>
  28#include <asm/processor.h>
  29#include <asm/mmu.h>
  30#include <asm/mmu_context.h>
  31#include <asm/prom.h>
  32#include <asm/machdep.h>
  33#include <asm/cputable.h>
  34#include <asm/sections.h>
  35#include <asm/firmware.h>
  36#include <asm/vdso.h>
  37#include <asm/vdso_datapage.h>
  38
  39#include "setup.h"
  40
  41#undef DEBUG
  42
  43#ifdef DEBUG
  44#define DBG(fmt...) printk(fmt)
  45#else
  46#define DBG(fmt...)
  47#endif
  48
  49/* Max supported size for symbol names */
  50#define MAX_SYMNAME     64
  51
  52extern char vdso32_start, vdso32_end;
  53static void *vdso32_kbase = &vdso32_start;
  54static unsigned int vdso32_pages;
  55static struct page **vdso32_pagelist;
  56unsigned long vdso32_sigtramp;
  57unsigned long vdso32_rt_sigtramp;
  58
  59#ifdef CONFIG_PPC64
  60extern char vdso64_start, vdso64_end;
  61static void *vdso64_kbase = &vdso64_start;
  62static unsigned int vdso64_pages;
  63static struct page **vdso64_pagelist;
  64unsigned long vdso64_rt_sigtramp;
  65#endif /* CONFIG_PPC64 */
  66
  67static int vdso_ready;
  68
  69/*
  70 * The vdso data page (aka. systemcfg for old ppc64 fans) is here.
  71 * Once the early boot kernel code no longer needs to muck around
  72 * with it, it will become dynamically allocated
  73 */
  74static union {
  75        struct vdso_data        data;
  76        u8                      page[PAGE_SIZE];
  77} vdso_data_store __attribute__((__section__(".data.page_aligned")));
  78struct vdso_data *vdso_data = &vdso_data_store.data;
  79
  80/* Format of the patch table */
  81struct vdso_patch_def
  82{
  83        unsigned long   ftr_mask, ftr_value;
  84        const char      *gen_name;
  85        const char      *fix_name;
  86};
  87
  88/* Table of functions to patch based on the CPU type/revision
  89 *
  90 * Currently, we only change sync_dicache to do nothing on processors
  91 * with a coherent icache
  92 */
  93static struct vdso_patch_def vdso_patches[] = {
  94        {
  95                CPU_FTR_COHERENT_ICACHE, CPU_FTR_COHERENT_ICACHE,
  96                "__kernel_sync_dicache", "__kernel_sync_dicache_p5"
  97        },
  98        {
  99                CPU_FTR_USE_TB, 0,
 100                "__kernel_gettimeofday", NULL
 101        },
 102        {
 103                CPU_FTR_USE_TB, 0,
 104                "__kernel_clock_gettime", NULL
 105        },
 106        {
 107                CPU_FTR_USE_TB, 0,
 108                "__kernel_clock_getres", NULL
 109        },
 110        {
 111                CPU_FTR_USE_TB, 0,
 112                "__kernel_get_tbfreq", NULL
 113        },
 114};
 115
 116/*
 117 * Some infos carried around for each of them during parsing at
 118 * boot time.
 119 */
 120struct lib32_elfinfo
 121{
 122        Elf32_Ehdr      *hdr;           /* ptr to ELF */
 123        Elf32_Sym       *dynsym;        /* ptr to .dynsym section */
 124        unsigned long   dynsymsize;     /* size of .dynsym section */
 125        char            *dynstr;        /* ptr to .dynstr section */
 126        unsigned long   text;           /* offset of .text section in .so */
 127};
 128
 129struct lib64_elfinfo
 130{
 131        Elf64_Ehdr      *hdr;
 132        Elf64_Sym       *dynsym;
 133        unsigned long   dynsymsize;
 134        char            *dynstr;
 135        unsigned long   text;
 136};
 137
 138
 139#ifdef __DEBUG
 140static void dump_one_vdso_page(struct page *pg, struct page *upg)
 141{
 142        printk("kpg: %p (c:%d,f:%08lx)", __va(page_to_pfn(pg) << PAGE_SHIFT),
 143               page_count(pg),
 144               pg->flags);
 145        if (upg && !IS_ERR(upg) /* && pg != upg*/) {
 146                printk(" upg: %p (c:%d,f:%08lx)", __va(page_to_pfn(upg)
 147                                                       << PAGE_SHIFT),
 148                       page_count(upg),
 149                       upg->flags);
 150        }
 151        printk("\n");
 152}
 153
 154static void dump_vdso_pages(struct vm_area_struct * vma)
 155{
 156        int i;
 157
 158        if (!vma || test_thread_flag(TIF_32BIT)) {
 159                printk("vDSO32 @ %016lx:\n", (unsigned long)vdso32_kbase);
 160                for (i=0; i<vdso32_pages; i++) {
 161                        struct page *pg = virt_to_page(vdso32_kbase +
 162                                                       i*PAGE_SIZE);
 163                        struct page *upg = (vma && vma->vm_mm) ?
 164                                follow_page(vma, vma->vm_start + i*PAGE_SIZE, 0)
 165                                : NULL;
 166                        dump_one_vdso_page(pg, upg);
 167                }
 168        }
 169        if (!vma || !test_thread_flag(TIF_32BIT)) {
 170                printk("vDSO64 @ %016lx:\n", (unsigned long)vdso64_kbase);
 171                for (i=0; i<vdso64_pages; i++) {
 172                        struct page *pg = virt_to_page(vdso64_kbase +
 173                                                       i*PAGE_SIZE);
 174                        struct page *upg = (vma && vma->vm_mm) ?
 175                                follow_page(vma, vma->vm_start + i*PAGE_SIZE, 0)
 176                                : NULL;
 177                        dump_one_vdso_page(pg, upg);
 178                }
 179        }
 180}
 181#endif /* DEBUG */
 182
 183/*
 184 * This is called from binfmt_elf, we create the special vma for the
 185 * vDSO and insert it into the mm struct tree
 186 */
 187int arch_setup_additional_pages(struct linux_binprm *bprm,
 188                                int executable_stack)
 189{
 190        struct mm_struct *mm = current->mm;
 191        struct page **vdso_pagelist;
 192        unsigned long vdso_pages;
 193        unsigned long vdso_base;
 194        int rc;
 195
 196        if (!vdso_ready)
 197                return 0;
 198
 199#ifdef CONFIG_PPC64
 200        if (test_thread_flag(TIF_32BIT)) {
 201                vdso_pagelist = vdso32_pagelist;
 202                vdso_pages = vdso32_pages;
 203                vdso_base = VDSO32_MBASE;
 204        } else {
 205                vdso_pagelist = vdso64_pagelist;
 206                vdso_pages = vdso64_pages;
 207                vdso_base = VDSO64_MBASE;
 208        }
 209#else
 210        vdso_pagelist = vdso32_pagelist;
 211        vdso_pages = vdso32_pages;
 212        vdso_base = VDSO32_MBASE;
 213#endif
 214
 215        current->mm->context.vdso_base = 0;
 216
 217        /* vDSO has a problem and was disabled, just don't "enable" it for the
 218         * process
 219         */
 220        if (vdso_pages == 0)
 221                return 0;
 222        /* Add a page to the vdso size for the data page */
 223        vdso_pages ++;
 224
 225        /*
 226         * pick a base address for the vDSO in process space. We try to put it
 227         * at vdso_base which is the "natural" base for it, but we might fail
 228         * and end up putting it elsewhere.
 229         */
 230        down_write(&mm->mmap_sem);
 231        vdso_base = get_unmapped_area(NULL, vdso_base,
 232                                      vdso_pages << PAGE_SHIFT, 0, 0);
 233        if (IS_ERR_VALUE(vdso_base)) {
 234                rc = vdso_base;
 235                goto fail_mmapsem;
 236        }
 237
 238        /*
 239         * our vma flags don't have VM_WRITE so by default, the process isn't
 240         * allowed to write those pages.
 241         * gdb can break that with ptrace interface, and thus trigger COW on
 242         * those pages but it's then your responsibility to never do that on
 243         * the "data" page of the vDSO or you'll stop getting kernel updates
 244         * and your nice userland gettimeofday will be totally dead.
 245         * It's fine to use that for setting breakpoints in the vDSO code
 246         * pages though
 247         *
 248         * Make sure the vDSO gets into every core dump.
 249         * Dumping its contents makes post-mortem fully interpretable later
 250         * without matching up the same kernel and hardware config to see
 251         * what PC values meant.
 252         */
 253        rc = install_special_mapping(mm, vdso_base, vdso_pages << PAGE_SHIFT,
 254                                     VM_READ|VM_EXEC|
 255                                     VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
 256                                     VM_ALWAYSDUMP,
 257                                     vdso_pagelist);
 258        if (rc)
 259                goto fail_mmapsem;
 260
 261        /* Put vDSO base into mm struct */
 262        current->mm->context.vdso_base = vdso_base;
 263
 264        up_write(&mm->mmap_sem);
 265        return 0;
 266
 267 fail_mmapsem:
 268        up_write(&mm->mmap_sem);
 269        return rc;
 270}
 271
 272const char *arch_vma_name(struct vm_area_struct *vma)
 273{
 274        if (vma->vm_mm && vma->vm_start == vma->vm_mm->context.vdso_base)
 275                return "[vdso]";
 276        return NULL;
 277}
 278
 279
 280
 281static void * __init find_section32(Elf32_Ehdr *ehdr, const char *secname,
 282                                  unsigned long *size)
 283{
 284        Elf32_Shdr *sechdrs;
 285        unsigned int i;
 286        char *secnames;
 287
 288        /* Grab section headers and strings so we can tell who is who */
 289        sechdrs = (void *)ehdr + ehdr->e_shoff;
 290        secnames = (void *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset;
 291
 292        /* Find the section they want */
 293        for (i = 1; i < ehdr->e_shnum; i++) {
 294                if (strcmp(secnames+sechdrs[i].sh_name, secname) == 0) {
 295                        if (size)
 296                                *size = sechdrs[i].sh_size;
 297                        return (void *)ehdr + sechdrs[i].sh_offset;
 298                }
 299        }
 300        *size = 0;
 301        return NULL;
 302}
 303
 304static Elf32_Sym * __init find_symbol32(struct lib32_elfinfo *lib,
 305                                        const char *symname)
 306{
 307        unsigned int i;
 308        char name[MAX_SYMNAME], *c;
 309
 310        for (i = 0; i < (lib->dynsymsize / sizeof(Elf32_Sym)); i++) {
 311                if (lib->dynsym[i].st_name == 0)
 312                        continue;
 313                strlcpy(name, lib->dynstr + lib->dynsym[i].st_name,
 314                        MAX_SYMNAME);
 315                c = strchr(name, '@');
 316                if (c)
 317                        *c = 0;
 318                if (strcmp(symname, name) == 0)
 319                        return &lib->dynsym[i];
 320        }
 321        return NULL;
 322}
 323
 324/* Note that we assume the section is .text and the symbol is relative to
 325 * the library base
 326 */
 327static unsigned long __init find_function32(struct lib32_elfinfo *lib,
 328                                            const char *symname)
 329{
 330        Elf32_Sym *sym = find_symbol32(lib, symname);
 331
 332        if (sym == NULL) {
 333                printk(KERN_WARNING "vDSO32: function %s not found !\n",
 334                       symname);
 335                return 0;
 336        }
 337        return sym->st_value - VDSO32_LBASE;
 338}
 339
 340static int __init vdso_do_func_patch32(struct lib32_elfinfo *v32,
 341                                       struct lib64_elfinfo *v64,
 342                                       const char *orig, const char *fix)
 343{
 344        Elf32_Sym *sym32_gen, *sym32_fix;
 345
 346        sym32_gen = find_symbol32(v32, orig);
 347        if (sym32_gen == NULL) {
 348                printk(KERN_ERR "vDSO32: Can't find symbol %s !\n", orig);
 349                return -1;
 350        }
 351        if (fix == NULL) {
 352                sym32_gen->st_name = 0;
 353                return 0;
 354        }
 355        sym32_fix = find_symbol32(v32, fix);
 356        if (sym32_fix == NULL) {
 357                printk(KERN_ERR "vDSO32: Can't find symbol %s !\n", fix);
 358                return -1;
 359        }
 360        sym32_gen->st_value = sym32_fix->st_value;
 361        sym32_gen->st_size = sym32_fix->st_size;
 362        sym32_gen->st_info = sym32_fix->st_info;
 363        sym32_gen->st_other = sym32_fix->st_other;
 364        sym32_gen->st_shndx = sym32_fix->st_shndx;
 365
 366        return 0;
 367}
 368
 369
 370#ifdef CONFIG_PPC64
 371
 372static void * __init find_section64(Elf64_Ehdr *ehdr, const char *secname,
 373                                  unsigned long *size)
 374{
 375        Elf64_Shdr *sechdrs;
 376        unsigned int i;
 377        char *secnames;
 378
 379        /* Grab section headers and strings so we can tell who is who */
 380        sechdrs = (void *)ehdr + ehdr->e_shoff;
 381        secnames = (void *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset;
 382
 383        /* Find the section they want */
 384        for (i = 1; i < ehdr->e_shnum; i++) {
 385                if (strcmp(secnames+sechdrs[i].sh_name, secname) == 0) {
 386                        if (size)
 387                                *size = sechdrs[i].sh_size;
 388                        return (void *)ehdr + sechdrs[i].sh_offset;
 389                }
 390        }
 391        if (size)
 392                *size = 0;
 393        return NULL;
 394}
 395
 396static Elf64_Sym * __init find_symbol64(struct lib64_elfinfo *lib,
 397                                        const char *symname)
 398{
 399        unsigned int i;
 400        char name[MAX_SYMNAME], *c;
 401
 402        for (i = 0; i < (lib->dynsymsize / sizeof(Elf64_Sym)); i++) {
 403                if (lib->dynsym[i].st_name == 0)
 404                        continue;
 405                strlcpy(name, lib->dynstr + lib->dynsym[i].st_name,
 406                        MAX_SYMNAME);
 407                c = strchr(name, '@');
 408                if (c)
 409                        *c = 0;
 410                if (strcmp(symname, name) == 0)
 411                        return &lib->dynsym[i];
 412        }
 413        return NULL;
 414}
 415
 416/* Note that we assume the section is .text and the symbol is relative to
 417 * the library base
 418 */
 419static unsigned long __init find_function64(struct lib64_elfinfo *lib,
 420                                            const char *symname)
 421{
 422        Elf64_Sym *sym = find_symbol64(lib, symname);
 423
 424        if (sym == NULL) {
 425                printk(KERN_WARNING "vDSO64: function %s not found !\n",
 426                       symname);
 427                return 0;
 428        }
 429#ifdef VDS64_HAS_DESCRIPTORS
 430        return *((u64 *)(vdso64_kbase + sym->st_value - VDSO64_LBASE)) -
 431                VDSO64_LBASE;
 432#else
 433        return sym->st_value - VDSO64_LBASE;
 434#endif
 435}
 436
 437static int __init vdso_do_func_patch64(struct lib32_elfinfo *v32,
 438                                       struct lib64_elfinfo *v64,
 439                                       const char *orig, const char *fix)
 440{
 441        Elf64_Sym *sym64_gen, *sym64_fix;
 442
 443        sym64_gen = find_symbol64(v64, orig);
 444        if (sym64_gen == NULL) {
 445                printk(KERN_ERR "vDSO64: Can't find symbol %s !\n", orig);
 446                return -1;
 447        }
 448        if (fix == NULL) {
 449                sym64_gen->st_name = 0;
 450                return 0;
 451        }
 452        sym64_fix = find_symbol64(v64, fix);
 453        if (sym64_fix == NULL) {
 454                printk(KERN_ERR "vDSO64: Can't find symbol %s !\n", fix);
 455                return -1;
 456        }
 457        sym64_gen->st_value = sym64_fix->st_value;
 458        sym64_gen->st_size = sym64_fix->st_size;
 459        sym64_gen->st_info = sym64_fix->st_info;
 460        sym64_gen->st_other = sym64_fix->st_other;
 461        sym64_gen->st_shndx = sym64_fix->st_shndx;
 462
 463        return 0;
 464}
 465
 466#endif /* CONFIG_PPC64 */
 467
 468
 469static __init int vdso_do_find_sections(struct lib32_elfinfo *v32,
 470                                        struct lib64_elfinfo *v64)
 471{
 472        void *sect;
 473
 474        /*
 475         * Locate symbol tables & text section
 476         */
 477
 478        v32->dynsym = find_section32(v32->hdr, ".dynsym", &v32->dynsymsize);
 479        v32->dynstr = find_section32(v32->hdr, ".dynstr", NULL);
 480        if (v32->dynsym == NULL || v32->dynstr == NULL) {
 481                printk(KERN_ERR "vDSO32: required symbol section not found\n");
 482                return -1;
 483        }
 484        sect = find_section32(v32->hdr, ".text", NULL);
 485        if (sect == NULL) {
 486                printk(KERN_ERR "vDSO32: the .text section was not found\n");
 487                return -1;
 488        }
 489        v32->text = sect - vdso32_kbase;
 490
 491#ifdef CONFIG_PPC64
 492        v64->dynsym = find_section64(v64->hdr, ".dynsym", &v64->dynsymsize);
 493        v64->dynstr = find_section64(v64->hdr, ".dynstr", NULL);
 494        if (v64->dynsym == NULL || v64->dynstr == NULL) {
 495                printk(KERN_ERR "vDSO64: required symbol section not found\n");
 496                return -1;
 497        }
 498        sect = find_section64(v64->hdr, ".text", NULL);
 499        if (sect == NULL) {
 500                printk(KERN_ERR "vDSO64: the .text section was not found\n");
 501                return -1;
 502        }
 503        v64->text = sect - vdso64_kbase;
 504#endif /* CONFIG_PPC64 */
 505
 506        return 0;
 507}
 508
 509static __init void vdso_setup_trampolines(struct lib32_elfinfo *v32,
 510                                          struct lib64_elfinfo *v64)
 511{
 512        /*
 513         * Find signal trampolines
 514         */
 515
 516#ifdef CONFIG_PPC64
 517        vdso64_rt_sigtramp = find_function64(v64, "__kernel_sigtramp_rt64");
 518#endif
 519        vdso32_sigtramp    = find_function32(v32, "__kernel_sigtramp32");
 520        vdso32_rt_sigtramp = find_function32(v32, "__kernel_sigtramp_rt32");
 521}
 522
 523static __init int vdso_fixup_datapage(struct lib32_elfinfo *v32,
 524                                       struct lib64_elfinfo *v64)
 525{
 526        Elf32_Sym *sym32;
 527#ifdef CONFIG_PPC64
 528        Elf64_Sym *sym64;
 529
 530        sym64 = find_symbol64(v64, "__kernel_datapage_offset");
 531        if (sym64 == NULL) {
 532                printk(KERN_ERR "vDSO64: Can't find symbol "
 533                       "__kernel_datapage_offset !\n");
 534                return -1;
 535        }
 536        *((int *)(vdso64_kbase + sym64->st_value - VDSO64_LBASE)) =
 537                (vdso64_pages << PAGE_SHIFT) -
 538                (sym64->st_value - VDSO64_LBASE);
 539#endif /* CONFIG_PPC64 */
 540
 541        sym32 = find_symbol32(v32, "__kernel_datapage_offset");
 542        if (sym32 == NULL) {
 543                printk(KERN_ERR "vDSO32: Can't find symbol "
 544                       "__kernel_datapage_offset !\n");
 545                return -1;
 546        }
 547        *((int *)(vdso32_kbase + (sym32->st_value - VDSO32_LBASE))) =
 548                (vdso32_pages << PAGE_SHIFT) -
 549                (sym32->st_value - VDSO32_LBASE);
 550
 551        return 0;
 552}
 553
 554
 555static __init int vdso_fixup_features(struct lib32_elfinfo *v32,
 556                                      struct lib64_elfinfo *v64)
 557{
 558        void *start32;
 559        unsigned long size32;
 560
 561#ifdef CONFIG_PPC64
 562        void *start64;
 563        unsigned long size64;
 564
 565        start64 = find_section64(v64->hdr, "__ftr_fixup", &size64);
 566        if (start64)
 567                do_feature_fixups(cur_cpu_spec->cpu_features,
 568                                  start64, start64 + size64);
 569
 570        start64 = find_section64(v64->hdr, "__fw_ftr_fixup", &size64);
 571        if (start64)
 572                do_feature_fixups(powerpc_firmware_features,
 573                                  start64, start64 + size64);
 574
 575        start64 = find_section64(v64->hdr, "__lwsync_fixup", &size64);
 576        if (start64)
 577                do_lwsync_fixups(cur_cpu_spec->cpu_features,
 578                                 start64, start64 + size64);
 579#endif /* CONFIG_PPC64 */
 580
 581        start32 = find_section32(v32->hdr, "__ftr_fixup", &size32);
 582        if (start32)
 583                do_feature_fixups(cur_cpu_spec->cpu_features,
 584                                  start32, start32 + size32);
 585
 586#ifdef CONFIG_PPC64
 587        start32 = find_section32(v32->hdr, "__fw_ftr_fixup", &size32);
 588        if (start32)
 589                do_feature_fixups(powerpc_firmware_features,
 590                                  start32, start32 + size32);
 591#endif /* CONFIG_PPC64 */
 592
 593        start32 = find_section32(v32->hdr, "__lwsync_fixup", &size32);
 594        if (start32)
 595                do_lwsync_fixups(cur_cpu_spec->cpu_features,
 596                                 start32, start32 + size32);
 597
 598        return 0;
 599}
 600
 601static __init int vdso_fixup_alt_funcs(struct lib32_elfinfo *v32,
 602                                       struct lib64_elfinfo *v64)
 603{
 604        int i;
 605
 606        for (i = 0; i < ARRAY_SIZE(vdso_patches); i++) {
 607                struct vdso_patch_def *patch = &vdso_patches[i];
 608                int match = (cur_cpu_spec->cpu_features & patch->ftr_mask)
 609                        == patch->ftr_value;
 610                if (!match)
 611                        continue;
 612
 613                DBG("replacing %s with %s...\n", patch->gen_name,
 614                    patch->fix_name ? "NONE" : patch->fix_name);
 615
 616                /*
 617                 * Patch the 32 bits and 64 bits symbols. Note that we do not
 618                 * patch the "." symbol on 64 bits.
 619                 * It would be easy to do, but doesn't seem to be necessary,
 620                 * patching the OPD symbol is enough.
 621                 */
 622                vdso_do_func_patch32(v32, v64, patch->gen_name,
 623                                     patch->fix_name);
 624#ifdef CONFIG_PPC64
 625                vdso_do_func_patch64(v32, v64, patch->gen_name,
 626                                     patch->fix_name);
 627#endif /* CONFIG_PPC64 */
 628        }
 629
 630        return 0;
 631}
 632
 633
 634static __init int vdso_setup(void)
 635{
 636        struct lib32_elfinfo    v32;
 637        struct lib64_elfinfo    v64;
 638
 639        v32.hdr = vdso32_kbase;
 640#ifdef CONFIG_PPC64
 641        v64.hdr = vdso64_kbase;
 642#endif
 643        if (vdso_do_find_sections(&v32, &v64))
 644                return -1;
 645
 646        if (vdso_fixup_datapage(&v32, &v64))
 647                return -1;
 648
 649        if (vdso_fixup_features(&v32, &v64))
 650                return -1;
 651
 652        if (vdso_fixup_alt_funcs(&v32, &v64))
 653                return -1;
 654
 655        vdso_setup_trampolines(&v32, &v64);
 656
 657        return 0;
 658}
 659
 660/*
 661 * Called from setup_arch to initialize the bitmap of available
 662 * syscalls in the systemcfg page
 663 */
 664static void __init vdso_setup_syscall_map(void)
 665{
 666        unsigned int i;
 667        extern unsigned long *sys_call_table;
 668        extern unsigned long sys_ni_syscall;
 669
 670
 671        for (i = 0; i < __NR_syscalls; i++) {
 672#ifdef CONFIG_PPC64
 673                if (sys_call_table[i*2] != sys_ni_syscall)
 674                        vdso_data->syscall_map_64[i >> 5] |=
 675                                0x80000000UL >> (i & 0x1f);
 676                if (sys_call_table[i*2+1] != sys_ni_syscall)
 677                        vdso_data->syscall_map_32[i >> 5] |=
 678                                0x80000000UL >> (i & 0x1f);
 679#else /* CONFIG_PPC64 */
 680                if (sys_call_table[i] != sys_ni_syscall)
 681                        vdso_data->syscall_map_32[i >> 5] |=
 682                                0x80000000UL >> (i & 0x1f);
 683#endif /* CONFIG_PPC64 */
 684        }
 685}
 686
 687
 688static int __init vdso_init(void)
 689{
 690        int i;
 691
 692#ifdef CONFIG_PPC64
 693        /*
 694         * Fill up the "systemcfg" stuff for backward compatiblity
 695         */
 696        strcpy((char *)vdso_data->eye_catcher, "SYSTEMCFG:PPC64");
 697        vdso_data->version.major = SYSTEMCFG_MAJOR;
 698        vdso_data->version.minor = SYSTEMCFG_MINOR;
 699        vdso_data->processor = mfspr(SPRN_PVR);
 700        /*
 701         * Fake the old platform number for pSeries and iSeries and add
 702         * in LPAR bit if necessary
 703         */
 704        vdso_data->platform = machine_is(iseries) ? 0x200 : 0x100;
 705        if (firmware_has_feature(FW_FEATURE_LPAR))
 706                vdso_data->platform |= 1;
 707        vdso_data->physicalMemorySize = lmb_phys_mem_size();
 708        vdso_data->dcache_size = ppc64_caches.dsize;
 709        vdso_data->dcache_line_size = ppc64_caches.dline_size;
 710        vdso_data->icache_size = ppc64_caches.isize;
 711        vdso_data->icache_line_size = ppc64_caches.iline_size;
 712
 713        /* XXXOJN: Blocks should be added to ppc64_caches and used instead */
 714        vdso_data->dcache_block_size = ppc64_caches.dline_size;
 715        vdso_data->icache_block_size = ppc64_caches.iline_size;
 716        vdso_data->dcache_log_block_size = ppc64_caches.log_dline_size;
 717        vdso_data->icache_log_block_size = ppc64_caches.log_iline_size;
 718
 719        /*
 720         * Calculate the size of the 64 bits vDSO
 721         */
 722        vdso64_pages = (&vdso64_end - &vdso64_start) >> PAGE_SHIFT;
 723        DBG("vdso64_kbase: %p, 0x%x pages\n", vdso64_kbase, vdso64_pages);
 724#else
 725        vdso_data->dcache_block_size = L1_CACHE_BYTES;
 726        vdso_data->dcache_log_block_size = L1_CACHE_SHIFT;
 727        vdso_data->icache_block_size = L1_CACHE_BYTES;
 728        vdso_data->icache_log_block_size = L1_CACHE_SHIFT;
 729#endif /* CONFIG_PPC64 */
 730
 731
 732        /*
 733         * Calculate the size of the 32 bits vDSO
 734         */
 735        vdso32_pages = (&vdso32_end - &vdso32_start) >> PAGE_SHIFT;
 736        DBG("vdso32_kbase: %p, 0x%x pages\n", vdso32_kbase, vdso32_pages);
 737
 738
 739        /*
 740         * Setup the syscall map in the vDOS
 741         */
 742        vdso_setup_syscall_map();
 743
 744        /*
 745         * Initialize the vDSO images in memory, that is do necessary
 746         * fixups of vDSO symbols, locate trampolines, etc...
 747         */
 748        if (vdso_setup()) {
 749                printk(KERN_ERR "vDSO setup failure, not enabled !\n");
 750                vdso32_pages = 0;
 751#ifdef CONFIG_PPC64
 752                vdso64_pages = 0;
 753#endif
 754                return 0;
 755        }
 756
 757        /* Make sure pages are in the correct state */
 758        vdso32_pagelist = kzalloc(sizeof(struct page *) * (vdso32_pages + 2),
 759                                  GFP_KERNEL);
 760        BUG_ON(vdso32_pagelist == NULL);
 761        for (i = 0; i < vdso32_pages; i++) {
 762                struct page *pg = virt_to_page(vdso32_kbase + i*PAGE_SIZE);
 763                ClearPageReserved(pg);
 764                get_page(pg);
 765                vdso32_pagelist[i] = pg;
 766        }
 767        vdso32_pagelist[i++] = virt_to_page(vdso_data);
 768        vdso32_pagelist[i] = NULL;
 769
 770#ifdef CONFIG_PPC64
 771        vdso64_pagelist = kzalloc(sizeof(struct page *) * (vdso64_pages + 2),
 772                                  GFP_KERNEL);
 773        BUG_ON(vdso64_pagelist == NULL);
 774        for (i = 0; i < vdso64_pages; i++) {
 775                struct page *pg = virt_to_page(vdso64_kbase + i*PAGE_SIZE);
 776                ClearPageReserved(pg);
 777                get_page(pg);
 778                vdso64_pagelist[i] = pg;
 779        }
 780        vdso64_pagelist[i++] = virt_to_page(vdso_data);
 781        vdso64_pagelist[i] = NULL;
 782#endif /* CONFIG_PPC64 */
 783
 784        get_page(virt_to_page(vdso_data));
 785
 786        smp_wmb();
 787        vdso_ready = 1;
 788
 789        return 0;
 790}
 791arch_initcall(vdso_init);
 792
 793int in_gate_area_no_task(unsigned long addr)
 794{
 795        return 0;
 796}
 797
 798int in_gate_area(struct task_struct *task, unsigned long addr)
 799{
 800        return 0;
 801}
 802
 803struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
 804{
 805        return NULL;
 806}
 807
 808
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.