linux/arch/powerpc/mm/pgtable_32.c
<<
>>
Prefs
   1/*
   2 * This file contains the routines setting up the linux page tables.
   3 *  -- paulus
   4 *
   5 *  Derived from arch/ppc/mm/init.c:
   6 *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
   7 *
   8 *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
   9 *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
  10 *    Copyright (C) 1996 Paul Mackerras
  11 *
  12 *  Derived from "arch/i386/mm/init.c"
  13 *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
  14 *
  15 *  This program is free software; you can redistribute it and/or
  16 *  modify it under the terms of the GNU General Public License
  17 *  as published by the Free Software Foundation; either version
  18 *  2 of the License, or (at your option) any later version.
  19 *
  20 */
  21
  22#include <linux/kernel.h>
  23#include <linux/module.h>
  24#include <linux/types.h>
  25#include <linux/mm.h>
  26#include <linux/vmalloc.h>
  27#include <linux/init.h>
  28#include <linux/highmem.h>
  29#include <linux/memblock.h>
  30#include <linux/slab.h>
  31
  32#include <asm/pgtable.h>
  33#include <asm/pgalloc.h>
  34#include <asm/fixmap.h>
  35#include <asm/io.h>
  36#include <asm/setup.h>
  37#include <asm/sections.h>
  38
  39#include "mmu_decl.h"
  40
  41unsigned long ioremap_bot;
  42EXPORT_SYMBOL(ioremap_bot);     /* aka VMALLOC_END */
  43
  44extern char etext[], _stext[], _sinittext[], _einittext[];
  45
  46__ref pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
  47{
  48        pte_t *pte;
  49
  50        if (slab_is_available()) {
  51                pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_ZERO);
  52        } else {
  53                pte = __va(memblock_alloc(PAGE_SIZE, PAGE_SIZE));
  54                if (pte)
  55                        clear_page(pte);
  56        }
  57        return pte;
  58}
  59
  60pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)
  61{
  62        struct page *ptepage;
  63
  64        gfp_t flags = GFP_KERNEL | __GFP_ZERO | __GFP_ACCOUNT;
  65
  66        ptepage = alloc_pages(flags, 0);
  67        if (!ptepage)
  68                return NULL;
  69        if (!pgtable_page_ctor(ptepage)) {
  70                __free_page(ptepage);
  71                return NULL;
  72        }
  73        return ptepage;
  74}
  75
  76void __iomem *
  77ioremap(phys_addr_t addr, unsigned long size)
  78{
  79        return __ioremap_caller(addr, size, _PAGE_NO_CACHE | _PAGE_GUARDED,
  80                                __builtin_return_address(0));
  81}
  82EXPORT_SYMBOL(ioremap);
  83
  84void __iomem *
  85ioremap_wc(phys_addr_t addr, unsigned long size)
  86{
  87        return __ioremap_caller(addr, size, _PAGE_NO_CACHE,
  88                                __builtin_return_address(0));
  89}
  90EXPORT_SYMBOL(ioremap_wc);
  91
  92void __iomem *
  93ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long flags)
  94{
  95        /* writeable implies dirty for kernel addresses */
  96        if ((flags & (_PAGE_RW | _PAGE_RO)) != _PAGE_RO)
  97                flags |= _PAGE_DIRTY | _PAGE_HWWRITE;
  98
  99        /* we don't want to let _PAGE_USER and _PAGE_EXEC leak out */
 100        flags &= ~(_PAGE_USER | _PAGE_EXEC);
 101
 102#ifdef _PAGE_BAP_SR
 103        /* _PAGE_USER contains _PAGE_BAP_SR on BookE using the new PTE format
 104         * which means that we just cleared supervisor access... oops ;-) This
 105         * restores it
 106         */
 107        flags |= _PAGE_BAP_SR;
 108#endif
 109
 110        return __ioremap_caller(addr, size, flags, __builtin_return_address(0));
 111}
 112EXPORT_SYMBOL(ioremap_prot);
 113
 114void __iomem *
 115__ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
 116{
 117        return __ioremap_caller(addr, size, flags, __builtin_return_address(0));
 118}
 119
 120void __iomem *
 121__ioremap_caller(phys_addr_t addr, unsigned long size, unsigned long flags,
 122                 void *caller)
 123{
 124        unsigned long v, i;
 125        phys_addr_t p;
 126        int err;
 127
 128        /* Make sure we have the base flags */
 129        if ((flags & _PAGE_PRESENT) == 0)
 130                flags |= pgprot_val(PAGE_KERNEL);
 131
 132        /* Non-cacheable page cannot be coherent */
 133        if (flags & _PAGE_NO_CACHE)
 134                flags &= ~_PAGE_COHERENT;
 135
 136        /*
 137         * Choose an address to map it to.
 138         * Once the vmalloc system is running, we use it.
 139         * Before then, we use space going down from IOREMAP_TOP
 140         * (ioremap_bot records where we're up to).
 141         */
 142        p = addr & PAGE_MASK;
 143        size = PAGE_ALIGN(addr + size) - p;
 144
 145        /*
 146         * If the address lies within the first 16 MB, assume it's in ISA
 147         * memory space
 148         */
 149        if (p < 16*1024*1024)
 150                p += _ISA_MEM_BASE;
 151
 152#ifndef CONFIG_CRASH_DUMP
 153        /*
 154         * Don't allow anybody to remap normal RAM that we're using.
 155         * mem_init() sets high_memory so only do the check after that.
 156         */
 157        if (slab_is_available() && (p < virt_to_phys(high_memory)) &&
 158            !(__allow_ioremap_reserved && memblock_is_region_reserved(p, size))) {
 159                printk("__ioremap(): phys addr 0x%llx is RAM lr %ps\n",
 160                       (unsigned long long)p, __builtin_return_address(0));
 161                return NULL;
 162        }
 163#endif
 164
 165        if (size == 0)
 166                return NULL;
 167
 168        /*
 169         * Is it already mapped?  Perhaps overlapped by a previous
 170         * mapping.
 171         */
 172        v = p_block_mapped(p);
 173        if (v)
 174                goto out;
 175
 176        if (slab_is_available()) {
 177                struct vm_struct *area;
 178                area = get_vm_area_caller(size, VM_IOREMAP, caller);
 179                if (area == 0)
 180                        return NULL;
 181                area->phys_addr = p;
 182                v = (unsigned long) area->addr;
 183        } else {
 184                v = (ioremap_bot -= size);
 185        }
 186
 187        /*
 188         * Should check if it is a candidate for a BAT mapping
 189         */
 190
 191        err = 0;
 192        for (i = 0; i < size && err == 0; i += PAGE_SIZE)
 193                err = map_kernel_page(v+i, p+i, flags);
 194        if (err) {
 195                if (slab_is_available())
 196                        vunmap((void *)v);
 197                return NULL;
 198        }
 199
 200out:
 201        return (void __iomem *) (v + ((unsigned long)addr & ~PAGE_MASK));
 202}
 203EXPORT_SYMBOL(__ioremap);
 204
 205void iounmap(volatile void __iomem *addr)
 206{
 207        /*
 208         * If mapped by BATs then there is nothing to do.
 209         * Calling vfree() generates a benign warning.
 210         */
 211        if (v_block_mapped((unsigned long)addr))
 212                return;
 213
 214        if (addr > high_memory && (unsigned long) addr < ioremap_bot)
 215                vunmap((void *) (PAGE_MASK & (unsigned long)addr));
 216}
 217EXPORT_SYMBOL(iounmap);
 218
 219int map_kernel_page(unsigned long va, phys_addr_t pa, int flags)
 220{
 221        pmd_t *pd;
 222        pte_t *pg;
 223        int err = -ENOMEM;
 224
 225        /* Use upper 10 bits of VA to index the first level map */
 226        pd = pmd_offset(pud_offset(pgd_offset_k(va), va), va);
 227        /* Use middle 10 bits of VA to index the second-level map */
 228        pg = pte_alloc_kernel(pd, va);
 229        if (pg != 0) {
 230                err = 0;
 231                /* The PTE should never be already set nor present in the
 232                 * hash table
 233                 */
 234                BUG_ON((pte_val(*pg) & (_PAGE_PRESENT | _PAGE_HASHPTE)) &&
 235                       flags);
 236                set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT,
 237                                                     __pgprot(flags)));
 238        }
 239        smp_wmb();
 240        return err;
 241}
 242
 243/*
 244 * Map in a chunk of physical memory starting at start.
 245 */
 246static void __init __mapin_ram_chunk(unsigned long offset, unsigned long top)
 247{
 248        unsigned long v, s, f;
 249        phys_addr_t p;
 250        int ktext;
 251
 252        s = offset;
 253        v = PAGE_OFFSET + s;
 254        p = memstart_addr + s;
 255        for (; s < top; s += PAGE_SIZE) {
 256                ktext = ((char *)v >= _stext && (char *)v < etext) ||
 257                        ((char *)v >= _sinittext && (char *)v < _einittext);
 258                f = ktext ? pgprot_val(PAGE_KERNEL_TEXT) : pgprot_val(PAGE_KERNEL);
 259                map_kernel_page(v, p, f);
 260#ifdef CONFIG_PPC_STD_MMU_32
 261                if (ktext)
 262                        hash_preload(&init_mm, v, 0, 0x300);
 263#endif
 264                v += PAGE_SIZE;
 265                p += PAGE_SIZE;
 266        }
 267}
 268
 269void __init mapin_ram(void)
 270{
 271        unsigned long s, top;
 272
 273#ifndef CONFIG_WII
 274        top = total_lowmem;
 275        s = mmu_mapin_ram(top);
 276        __mapin_ram_chunk(s, top);
 277#else
 278        if (!wii_hole_size) {
 279                s = mmu_mapin_ram(total_lowmem);
 280                __mapin_ram_chunk(s, total_lowmem);
 281        } else {
 282                top = wii_hole_start;
 283                s = mmu_mapin_ram(top);
 284                __mapin_ram_chunk(s, top);
 285
 286                top = memblock_end_of_DRAM();
 287                s = wii_mmu_mapin_mem2(top);
 288                __mapin_ram_chunk(s, top);
 289        }
 290#endif
 291}
 292
 293/* Scan the real Linux page tables and return a PTE pointer for
 294 * a virtual address in a context.
 295 * Returns true (1) if PTE was found, zero otherwise.  The pointer to
 296 * the PTE pointer is unmodified if PTE is not found.
 297 */
 298static int
 299get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep, pmd_t **pmdp)
 300{
 301        pgd_t   *pgd;
 302        pud_t   *pud;
 303        pmd_t   *pmd;
 304        pte_t   *pte;
 305        int     retval = 0;
 306
 307        pgd = pgd_offset(mm, addr & PAGE_MASK);
 308        if (pgd) {
 309                pud = pud_offset(pgd, addr & PAGE_MASK);
 310                if (pud && pud_present(*pud)) {
 311                        pmd = pmd_offset(pud, addr & PAGE_MASK);
 312                        if (pmd_present(*pmd)) {
 313                                pte = pte_offset_map(pmd, addr & PAGE_MASK);
 314                                if (pte) {
 315                                        retval = 1;
 316                                        *ptep = pte;
 317                                        if (pmdp)
 318                                                *pmdp = pmd;
 319                                        /* XXX caller needs to do pte_unmap, yuck */
 320                                }
 321                        }
 322                }
 323        }
 324        return(retval);
 325}
 326
 327static int __change_page_attr_noflush(struct page *page, pgprot_t prot)
 328{
 329        pte_t *kpte;
 330        pmd_t *kpmd;
 331        unsigned long address;
 332
 333        BUG_ON(PageHighMem(page));
 334        address = (unsigned long)page_address(page);
 335
 336        if (v_block_mapped(address))
 337                return 0;
 338        if (!get_pteptr(&init_mm, address, &kpte, &kpmd))
 339                return -EINVAL;
 340        __set_pte_at(&init_mm, address, kpte, mk_pte(page, prot), 0);
 341        pte_unmap(kpte);
 342
 343        return 0;
 344}
 345
 346/*
 347 * Change the page attributes of an page in the linear mapping.
 348 *
 349 * THIS DOES NOTHING WITH BAT MAPPINGS, DEBUG USE ONLY
 350 */
 351static int change_page_attr(struct page *page, int numpages, pgprot_t prot)
 352{
 353        int i, err = 0;
 354        unsigned long flags;
 355        struct page *start = page;
 356
 357        local_irq_save(flags);
 358        for (i = 0; i < numpages; i++, page++) {
 359                err = __change_page_attr_noflush(page, prot);
 360                if (err)
 361                        break;
 362        }
 363        wmb();
 364        local_irq_restore(flags);
 365        flush_tlb_kernel_range((unsigned long)page_address(start),
 366                               (unsigned long)page_address(page));
 367        return err;
 368}
 369
 370void mark_initmem_nx(void)
 371{
 372        struct page *page = virt_to_page(_sinittext);
 373        unsigned long numpages = PFN_UP((unsigned long)_einittext) -
 374                                 PFN_DOWN((unsigned long)_sinittext);
 375
 376        change_page_attr(page, numpages, PAGE_KERNEL);
 377}
 378
 379#ifdef CONFIG_STRICT_KERNEL_RWX
 380void mark_rodata_ro(void)
 381{
 382        struct page *page;
 383        unsigned long numpages;
 384
 385        page = virt_to_page(_stext);
 386        numpages = PFN_UP((unsigned long)_etext) -
 387                   PFN_DOWN((unsigned long)_stext);
 388
 389        change_page_attr(page, numpages, PAGE_KERNEL_ROX);
 390        /*
 391         * mark .rodata as read only. Use __init_begin rather than __end_rodata
 392         * to cover NOTES and EXCEPTION_TABLE.
 393         */
 394        page = virt_to_page(__start_rodata);
 395        numpages = PFN_UP((unsigned long)__init_begin) -
 396                   PFN_DOWN((unsigned long)__start_rodata);
 397
 398        change_page_attr(page, numpages, PAGE_KERNEL_RO);
 399}
 400#endif
 401
 402#ifdef CONFIG_DEBUG_PAGEALLOC
 403void __kernel_map_pages(struct page *page, int numpages, int enable)
 404{
 405        if (PageHighMem(page))
 406                return;
 407
 408        change_page_attr(page, numpages, enable ? PAGE_KERNEL : __pgprot(0));
 409}
 410#endif /* CONFIG_DEBUG_PAGEALLOC */
 411