1 /* 2 * linux/arch/arm/mm/pgd.c 3 * 4 * Copyright (C) 1998-2005 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 #include <linux/mm.h> 11 #include <linux/gfp.h> 12 #include <linux/highmem.h> 13 14 #include <asm/pgalloc.h> 15 #include <asm/page.h> 16 #include <asm/tlbflush.h> 17 18 #include "mm.h" 19 20 /* 21 * need to get a 16k page for level 1 22 */ 23 pgd_t *pgd_alloc(struct mm_struct *mm) 24 { 25 pgd_t *new_pgd, *init_pgd; 26 pmd_t *new_pmd, *init_pmd; 27 pte_t *new_pte, *init_pte; 28 29 new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 2); 30 if (!new_pgd) 31 goto no_pgd; 32 33 memset(new_pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); 34 35 /* 36 * Copy over the kernel and IO PGD entries 37 */ 38 init_pgd = pgd_offset_k(0); 39 memcpy(new_pgd + USER_PTRS_PER_PGD, init_pgd + USER_PTRS_PER_PGD, 40 (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); 41 42 clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t)); 43 44 if (!vectors_high()) { 45 /* 46 * On ARM, first page must always be allocated since it 47 * contains the machine vectors. 48 */ 49 new_pmd = pmd_alloc(mm, new_pgd, 0); 50 if (!new_pmd) 51 goto no_pmd; 52 53 new_pte = pte_alloc_map(mm, NULL, new_pmd, 0); 54 if (!new_pte) 55 goto no_pte; 56 57 init_pmd = pmd_offset(init_pgd, 0); 58 init_pte = pte_offset_map(init_pmd, 0); 59 set_pte_ext(new_pte, *init_pte, 0); 60 pte_unmap(init_pte); 61 pte_unmap(new_pte); 62 } 63 64 return new_pgd; 65 66 no_pte: 67 pmd_free(mm, new_pmd); 68 no_pmd: 69 free_pages((unsigned long)new_pgd, 2); 70 no_pgd: 71 return NULL; 72 } 73 74 void pgd_free(struct mm_struct *mm, pgd_t *pgd_base) 75 { 76 pgd_t *pgd; 77 pmd_t *pmd; 78 pgtable_t pte; 79 80 if (!pgd_base) 81 return; 82 83 pgd = pgd_base + pgd_index(0); 84 if (pgd_none_or_clear_bad(pgd)) 85 goto no_pgd; 86 87 pmd = pmd_offset(pgd, 0); 88 if (pmd_none_or_clear_bad(pmd)) 89 goto no_pmd; 90 91 pte = pmd_pgtable(*pmd); 92 pmd_clear(pmd); 93 pte_free(mm, pte); 94 no_pmd: 95 pgd_clear(pgd); 96 pmd_free(mm, pmd); 97 no_pgd: 98 free_pages((unsigned long) pgd_base, 2); 99 } 100