linux/arch/arm/include/asm/pgalloc.h
<<
>>
Prefs
   1/*
   2 *  arch/arm/include/asm/pgalloc.h
   3 *
   4 *  Copyright (C) 2000-2001 Russell King
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10#ifndef _ASMARM_PGALLOC_H
  11#define _ASMARM_PGALLOC_H
  12
  13#include <asm/domain.h>
  14#include <asm/pgtable-hwdef.h>
  15#include <asm/processor.h>
  16#include <asm/cacheflush.h>
  17#include <asm/tlbflush.h>
  18
  19#define check_pgt_cache()               do { } while (0)
  20
  21#ifdef CONFIG_MMU
  22
  23#define _PAGE_USER_TABLE        (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_USER))
  24#define _PAGE_KERNEL_TABLE      (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_KERNEL))
  25
  26/*
  27 * Since we have only two-level page tables, these are trivial
  28 */
  29#define pmd_alloc_one(mm,addr)          ({ BUG(); ((pmd_t *)2); })
  30#define pmd_free(mm, pmd)               do { } while (0)
  31#define pgd_populate(mm,pmd,pte)        BUG()
  32
  33extern pgd_t *get_pgd_slow(struct mm_struct *mm);
  34extern void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd);
  35
  36#define pgd_alloc(mm)                   get_pgd_slow(mm)
  37#define pgd_free(mm, pgd)               free_pgd_slow(mm, pgd)
  38
  39#define PGALLOC_GFP     (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO)
  40
  41/*
  42 * Allocate one PTE table.
  43 *
  44 * This actually allocates two hardware PTE tables, but we wrap this up
  45 * into one table thus:
  46 *
  47 *  +------------+
  48 *  |  h/w pt 0  |
  49 *  +------------+
  50 *  |  h/w pt 1  |
  51 *  +------------+
  52 *  | Linux pt 0 |
  53 *  +------------+
  54 *  | Linux pt 1 |
  55 *  +------------+
  56 */
  57static inline pte_t *
  58pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr)
  59{
  60        pte_t *pte;
  61
  62        pte = (pte_t *)__get_free_page(PGALLOC_GFP);
  63        if (pte) {
  64                clean_dcache_area(pte, sizeof(pte_t) * PTRS_PER_PTE);
  65                pte += PTRS_PER_PTE;
  66        }
  67
  68        return pte;
  69}
  70
  71static inline pgtable_t
  72pte_alloc_one(struct mm_struct *mm, unsigned long addr)
  73{
  74        struct page *pte;
  75
  76#ifdef CONFIG_HIGHPTE
  77        pte = alloc_pages(PGALLOC_GFP | __GFP_HIGHMEM, 0);
  78#else
  79        pte = alloc_pages(PGALLOC_GFP, 0);
  80#endif
  81        if (pte) {
  82                if (!PageHighMem(pte)) {
  83                        void *page = page_address(pte);
  84                        clean_dcache_area(page, sizeof(pte_t) * PTRS_PER_PTE);
  85                }
  86                pgtable_page_ctor(pte);
  87        }
  88
  89        return pte;
  90}
  91
  92/*
  93 * Free one PTE table.
  94 */
  95static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
  96{
  97        if (pte) {
  98                pte -= PTRS_PER_PTE;
  99                free_page((unsigned long)pte);
 100        }
 101}
 102
 103static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
 104{
 105        pgtable_page_dtor(pte);
 106        __free_page(pte);
 107}
 108
 109static inline void __pmd_populate(pmd_t *pmdp, unsigned long pmdval)
 110{
 111        pmdp[0] = __pmd(pmdval);
 112        pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
 113        flush_pmd_entry(pmdp);
 114}
 115
 116/*
 117 * Populate the pmdp entry with a pointer to the pte.  This pmd is part
 118 * of the mm address space.
 119 *
 120 * Ensure that we always set both PMD entries.
 121 */
 122static inline void
 123pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
 124{
 125        unsigned long pte_ptr = (unsigned long)ptep;
 126
 127        /*
 128         * The pmd must be loaded with the physical
 129         * address of the PTE table
 130         */
 131        pte_ptr -= PTRS_PER_PTE * sizeof(void *);
 132        __pmd_populate(pmdp, __pa(pte_ptr) | _PAGE_KERNEL_TABLE);
 133}
 134
 135static inline void
 136pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep)
 137{
 138        __pmd_populate(pmdp, page_to_pfn(ptep) << PAGE_SHIFT | _PAGE_USER_TABLE);
 139}
 140#define pmd_pgtable(pmd) pmd_page(pmd)
 141
 142#endif /* CONFIG_MMU */
 143
 144#endif
 145