10c668984SRussell King /* 20c668984SRussell King * linux/arch/arm/mm/pgd.c 30c668984SRussell King * 40c668984SRussell King * Copyright (C) 1998-2005 Russell King 50c668984SRussell King * 60c668984SRussell King * This program is free software; you can redistribute it and/or modify 70c668984SRussell King * it under the terms of the GNU General Public License version 2 as 80c668984SRussell King * published by the Free Software Foundation. 90c668984SRussell King */ 100c668984SRussell King #include <linux/mm.h> 115a0e3ad6STejun Heo #include <linux/gfp.h> 120c668984SRussell King #include <linux/highmem.h> 13*da028779SCatalin Marinas #include <linux/slab.h> 140c668984SRussell King 150c668984SRussell King #include <asm/pgalloc.h> 160c668984SRussell King #include <asm/page.h> 170c668984SRussell King #include <asm/tlbflush.h> 180c668984SRussell King 190c668984SRussell King #include "mm.h" 200c668984SRussell King 21*da028779SCatalin Marinas #ifdef CONFIG_ARM_LPAE 22*da028779SCatalin Marinas #define __pgd_alloc() kmalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL) 23*da028779SCatalin Marinas #define __pgd_free(pgd) kfree(pgd) 24*da028779SCatalin Marinas #else 25*da028779SCatalin Marinas #define __pgd_alloc() (pgd_t *)__get_free_pages(GFP_KERNEL, 2) 26*da028779SCatalin Marinas #define __pgd_free(pgd) free_pages((unsigned long)pgd, 2) 27*da028779SCatalin Marinas #endif 28*da028779SCatalin Marinas 290c668984SRussell King /* 300c668984SRussell King * need to get a 16k page for level 1 310c668984SRussell King */ 32b0d03745SRussell King pgd_t *pgd_alloc(struct mm_struct *mm) 330c668984SRussell King { 340c668984SRussell King pgd_t *new_pgd, *init_pgd; 35516295e5SRussell King pud_t *new_pud, *init_pud; 360c668984SRussell King pmd_t *new_pmd, *init_pmd; 370c668984SRussell King pte_t *new_pte, *init_pte; 380c668984SRussell King 39*da028779SCatalin Marinas new_pgd = __pgd_alloc(); 400c668984SRussell King if (!new_pgd) 410c668984SRussell King goto no_pgd; 420c668984SRussell King 43e926f449SRussell King memset(new_pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); 440c668984SRussell King 450c668984SRussell King /* 460c668984SRussell King * Copy over the kernel and IO PGD entries 470c668984SRussell King */ 480c668984SRussell King init_pgd = pgd_offset_k(0); 49e926f449SRussell King memcpy(new_pgd + USER_PTRS_PER_PGD, init_pgd + USER_PTRS_PER_PGD, 50e926f449SRussell King (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); 510c668984SRussell King 520c668984SRussell King clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t)); 530c668984SRussell King 54*da028779SCatalin Marinas #ifdef CONFIG_ARM_LPAE 55*da028779SCatalin Marinas /* 56*da028779SCatalin Marinas * Allocate PMD table for modules and pkmap mappings. 57*da028779SCatalin Marinas */ 58*da028779SCatalin Marinas new_pud = pud_alloc(mm, new_pgd + pgd_index(MODULES_VADDR), 59*da028779SCatalin Marinas MODULES_VADDR); 60*da028779SCatalin Marinas if (!new_pud) 61*da028779SCatalin Marinas goto no_pud; 62*da028779SCatalin Marinas 63*da028779SCatalin Marinas new_pmd = pmd_alloc(mm, new_pud, 0); 64*da028779SCatalin Marinas if (!new_pmd) 65*da028779SCatalin Marinas goto no_pmd; 66*da028779SCatalin Marinas #endif 67*da028779SCatalin Marinas 680c668984SRussell King if (!vectors_high()) { 690c668984SRussell King /* 700c668984SRussell King * On ARM, first page must always be allocated since it 71*da028779SCatalin Marinas * contains the machine vectors. The vectors are always high 72*da028779SCatalin Marinas * with LPAE. 730c668984SRussell King */ 74516295e5SRussell King new_pud = pud_alloc(mm, new_pgd, 0); 75516295e5SRussell King if (!new_pud) 76516295e5SRussell King goto no_pud; 77516295e5SRussell King 78516295e5SRussell King new_pmd = pmd_alloc(mm, new_pud, 0); 790c668984SRussell King if (!new_pmd) 800c668984SRussell King goto no_pmd; 810c668984SRussell King 828ac1f832SAndrea Arcangeli new_pte = pte_alloc_map(mm, NULL, new_pmd, 0); 830c668984SRussell King if (!new_pte) 840c668984SRussell King goto no_pte; 850c668984SRussell King 86516295e5SRussell King init_pud = pud_offset(init_pgd, 0); 87516295e5SRussell King init_pmd = pmd_offset(init_pud, 0); 88ece0e2b6SPeter Zijlstra init_pte = pte_offset_map(init_pmd, 0); 89ad1ae2feSRussell King set_pte_ext(new_pte, *init_pte, 0); 90ece0e2b6SPeter Zijlstra pte_unmap(init_pte); 910c668984SRussell King pte_unmap(new_pte); 920c668984SRussell King } 930c668984SRussell King 940c668984SRussell King return new_pgd; 950c668984SRussell King 960c668984SRussell King no_pte: 975e541973SBenjamin Herrenschmidt pmd_free(mm, new_pmd); 980c668984SRussell King no_pmd: 99516295e5SRussell King pud_free(mm, new_pud); 100516295e5SRussell King no_pud: 101*da028779SCatalin Marinas __pgd_free(new_pgd); 1020c668984SRussell King no_pgd: 1030c668984SRussell King return NULL; 1040c668984SRussell King } 1050c668984SRussell King 1066e4beb5eSRussell King void pgd_free(struct mm_struct *mm, pgd_t *pgd_base) 1070c668984SRussell King { 1086e4beb5eSRussell King pgd_t *pgd; 109516295e5SRussell King pud_t *pud; 1100c668984SRussell King pmd_t *pmd; 1110c82d83cSUwe Kleine-König pgtable_t pte; 1120c668984SRussell King 1136e4beb5eSRussell King if (!pgd_base) 1140c668984SRussell King return; 1150c668984SRussell King 1166e4beb5eSRussell King pgd = pgd_base + pgd_index(0); 1176e4beb5eSRussell King if (pgd_none_or_clear_bad(pgd)) 1186e4beb5eSRussell King goto no_pgd; 1196e4beb5eSRussell King 120516295e5SRussell King pud = pud_offset(pgd, 0); 121516295e5SRussell King if (pud_none_or_clear_bad(pud)) 122516295e5SRussell King goto no_pud; 123516295e5SRussell King 124516295e5SRussell King pmd = pmd_offset(pud, 0); 1256e4beb5eSRussell King if (pmd_none_or_clear_bad(pmd)) 1266e4beb5eSRussell King goto no_pmd; 1270c668984SRussell King 1280c82d83cSUwe Kleine-König pte = pmd_pgtable(*pmd); 1290c668984SRussell King pmd_clear(pmd); 1305e541973SBenjamin Herrenschmidt pte_free(mm, pte); 1316e4beb5eSRussell King no_pmd: 132516295e5SRussell King pud_clear(pud); 1335e541973SBenjamin Herrenschmidt pmd_free(mm, pmd); 134516295e5SRussell King no_pud: 135516295e5SRussell King pgd_clear(pgd); 136516295e5SRussell King pud_free(mm, pud); 1376e4beb5eSRussell King no_pgd: 138*da028779SCatalin Marinas #ifdef CONFIG_ARM_LPAE 139*da028779SCatalin Marinas /* 140*da028779SCatalin Marinas * Free modules/pkmap or identity pmd tables. 141*da028779SCatalin Marinas */ 142*da028779SCatalin Marinas for (pgd = pgd_base; pgd < pgd_base + PTRS_PER_PGD; pgd++) { 143*da028779SCatalin Marinas if (pgd_none_or_clear_bad(pgd)) 144*da028779SCatalin Marinas continue; 145*da028779SCatalin Marinas if (pgd_val(*pgd) & L_PGD_SWAPPER) 146*da028779SCatalin Marinas continue; 147*da028779SCatalin Marinas pud = pud_offset(pgd, 0); 148*da028779SCatalin Marinas if (pud_none_or_clear_bad(pud)) 149*da028779SCatalin Marinas continue; 150*da028779SCatalin Marinas pmd = pmd_offset(pud, 0); 151*da028779SCatalin Marinas pud_clear(pud); 152*da028779SCatalin Marinas pmd_free(mm, pmd); 153*da028779SCatalin Marinas pgd_clear(pgd); 154*da028779SCatalin Marinas pud_free(mm, pud); 155*da028779SCatalin Marinas } 156*da028779SCatalin Marinas #endif 157*da028779SCatalin Marinas __pgd_free(pgd_base); 1580c668984SRussell King } 159