1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 20c668984SRussell King /* 30c668984SRussell King * linux/arch/arm/mm/pgd.c 40c668984SRussell King * 50c668984SRussell King * Copyright (C) 1998-2005 Russell King 60c668984SRussell King */ 70c668984SRussell King #include <linux/mm.h> 85a0e3ad6STejun Heo #include <linux/gfp.h> 90c668984SRussell King #include <linux/highmem.h> 10da028779SCatalin Marinas #include <linux/slab.h> 110c668984SRussell King 1215d07dc9SRussell King #include <asm/cp15.h> 130c668984SRussell King #include <asm/pgalloc.h> 140c668984SRussell King #include <asm/page.h> 150c668984SRussell King #include <asm/tlbflush.h> 160c668984SRussell King 170c668984SRussell King #include "mm.h" 180c668984SRussell King 19da028779SCatalin Marinas #ifdef CONFIG_ARM_LPAE 206da2ec56SKees Cook #define __pgd_alloc() kmalloc_array(PTRS_PER_PGD, sizeof(pgd_t), GFP_KERNEL) 21da028779SCatalin Marinas #define __pgd_free(pgd) kfree(pgd) 22da028779SCatalin Marinas #else 23397b080bSMichal Hocko #define __pgd_alloc() (pgd_t *)__get_free_pages(GFP_KERNEL, 2) 24da028779SCatalin Marinas #define __pgd_free(pgd) free_pages((unsigned long)pgd, 2) 25da028779SCatalin Marinas #endif 26da028779SCatalin Marinas 270c668984SRussell King /* 280c668984SRussell King * need to get a 16k page for level 1 290c668984SRussell King */ 30b0d03745SRussell King pgd_t *pgd_alloc(struct mm_struct *mm) 310c668984SRussell King { 320c668984SRussell King pgd_t *new_pgd, *init_pgd; 3384e6ffb2SMike Rapoport p4d_t *new_p4d, *init_p4d; 34516295e5SRussell King pud_t *new_pud, *init_pud; 350c668984SRussell King pmd_t *new_pmd, *init_pmd; 360c668984SRussell King pte_t *new_pte, *init_pte; 370c668984SRussell King 38da028779SCatalin Marinas new_pgd = __pgd_alloc(); 390c668984SRussell King if (!new_pgd) 400c668984SRussell King goto no_pgd; 410c668984SRussell King 42e926f449SRussell King memset(new_pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); 430c668984SRussell King 440c668984SRussell King /* 450c668984SRussell King * Copy over the kernel and IO PGD entries 460c668984SRussell King */ 470c668984SRussell King init_pgd = pgd_offset_k(0); 48e926f449SRussell King memcpy(new_pgd + USER_PTRS_PER_PGD, init_pgd + USER_PTRS_PER_PGD, 49e926f449SRussell King (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); 500c668984SRussell King 510c668984SRussell King clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t)); 520c668984SRussell King 53da028779SCatalin Marinas #ifdef CONFIG_ARM_LPAE 54da028779SCatalin Marinas /* 55da028779SCatalin Marinas * Allocate PMD table for modules and pkmap mappings. 56da028779SCatalin Marinas */ 5784e6ffb2SMike Rapoport new_p4d = p4d_alloc(mm, new_pgd + pgd_index(MODULES_VADDR), 58da028779SCatalin Marinas MODULES_VADDR); 5984e6ffb2SMike Rapoport if (!new_p4d) 6084e6ffb2SMike Rapoport goto no_p4d; 6184e6ffb2SMike Rapoport 6284e6ffb2SMike Rapoport new_pud = pud_alloc(mm, new_p4d, MODULES_VADDR); 63da028779SCatalin Marinas if (!new_pud) 64da028779SCatalin Marinas goto no_pud; 65da028779SCatalin Marinas 66da028779SCatalin Marinas new_pmd = pmd_alloc(mm, new_pud, 0); 67da028779SCatalin Marinas if (!new_pmd) 68da028779SCatalin Marinas goto no_pmd; 69*5615f69bSLinus Walleij #ifdef CONFIG_KASAN 70*5615f69bSLinus Walleij /* 71*5615f69bSLinus Walleij * Copy PMD table for KASAN shadow mappings. 72*5615f69bSLinus Walleij */ 73*5615f69bSLinus Walleij init_pgd = pgd_offset_k(TASK_SIZE); 74*5615f69bSLinus Walleij init_p4d = p4d_offset(init_pgd, TASK_SIZE); 75*5615f69bSLinus Walleij init_pud = pud_offset(init_p4d, TASK_SIZE); 76*5615f69bSLinus Walleij init_pmd = pmd_offset(init_pud, TASK_SIZE); 77*5615f69bSLinus Walleij new_pmd = pmd_offset(new_pud, TASK_SIZE); 78*5615f69bSLinus Walleij memcpy(new_pmd, init_pmd, 79*5615f69bSLinus Walleij (pmd_index(MODULES_VADDR) - pmd_index(TASK_SIZE)) 80*5615f69bSLinus Walleij * sizeof(pmd_t)); 81*5615f69bSLinus Walleij clean_dcache_area(new_pmd, PTRS_PER_PMD * sizeof(pmd_t)); 82*5615f69bSLinus Walleij #endif /* CONFIG_KASAN */ 83*5615f69bSLinus Walleij #endif /* CONFIG_LPAE */ 84da028779SCatalin Marinas 850c668984SRussell King if (!vectors_high()) { 860c668984SRussell King /* 870c668984SRussell King * On ARM, first page must always be allocated since it 88da028779SCatalin Marinas * contains the machine vectors. The vectors are always high 89da028779SCatalin Marinas * with LPAE. 900c668984SRussell King */ 9184e6ffb2SMike Rapoport new_p4d = p4d_alloc(mm, new_pgd, 0); 9284e6ffb2SMike Rapoport if (!new_p4d) 9384e6ffb2SMike Rapoport goto no_p4d; 9484e6ffb2SMike Rapoport 9584e6ffb2SMike Rapoport new_pud = pud_alloc(mm, new_p4d, 0); 96516295e5SRussell King if (!new_pud) 97516295e5SRussell King goto no_pud; 98516295e5SRussell King 99516295e5SRussell King new_pmd = pmd_alloc(mm, new_pud, 0); 1000c668984SRussell King if (!new_pmd) 1010c668984SRussell King goto no_pmd; 1020c668984SRussell King 1033ed3a4f0SKirill A. Shutemov new_pte = pte_alloc_map(mm, new_pmd, 0); 1040c668984SRussell King if (!new_pte) 1050c668984SRussell King goto no_pte; 1060c668984SRussell King 107a02d8dfdSRussell King #ifndef CONFIG_ARM_LPAE 108a02d8dfdSRussell King /* 109a02d8dfdSRussell King * Modify the PTE pointer to have the correct domain. This 110a02d8dfdSRussell King * needs to be the vectors domain to avoid the low vectors 111a02d8dfdSRussell King * being unmapped. 112a02d8dfdSRussell King */ 113a02d8dfdSRussell King pmd_val(*new_pmd) &= ~PMD_DOMAIN_MASK; 114a02d8dfdSRussell King pmd_val(*new_pmd) |= PMD_DOMAIN(DOMAIN_VECTORS); 115a02d8dfdSRussell King #endif 116a02d8dfdSRussell King 11784e6ffb2SMike Rapoport init_p4d = p4d_offset(init_pgd, 0); 11884e6ffb2SMike Rapoport init_pud = pud_offset(init_p4d, 0); 119516295e5SRussell King init_pmd = pmd_offset(init_pud, 0); 120ece0e2b6SPeter Zijlstra init_pte = pte_offset_map(init_pmd, 0); 121d8aa712cSRussell King set_pte_ext(new_pte + 0, init_pte[0], 0); 122d8aa712cSRussell King set_pte_ext(new_pte + 1, init_pte[1], 0); 123ece0e2b6SPeter Zijlstra pte_unmap(init_pte); 1240c668984SRussell King pte_unmap(new_pte); 1250c668984SRussell King } 1260c668984SRussell King 1270c668984SRussell King return new_pgd; 1280c668984SRussell King 1290c668984SRussell King no_pte: 1305e541973SBenjamin Herrenschmidt pmd_free(mm, new_pmd); 131b30fe6c7SKirill A. Shutemov mm_dec_nr_pmds(mm); 1320c668984SRussell King no_pmd: 133516295e5SRussell King pud_free(mm, new_pud); 134516295e5SRussell King no_pud: 13584e6ffb2SMike Rapoport p4d_free(mm, new_p4d); 13684e6ffb2SMike Rapoport no_p4d: 137da028779SCatalin Marinas __pgd_free(new_pgd); 1380c668984SRussell King no_pgd: 1390c668984SRussell King return NULL; 1400c668984SRussell King } 1410c668984SRussell King 1426e4beb5eSRussell King void pgd_free(struct mm_struct *mm, pgd_t *pgd_base) 1430c668984SRussell King { 1446e4beb5eSRussell King pgd_t *pgd; 14584e6ffb2SMike Rapoport p4d_t *p4d; 146516295e5SRussell King pud_t *pud; 1470c668984SRussell King pmd_t *pmd; 1480c82d83cSUwe Kleine-König pgtable_t pte; 1490c668984SRussell King 1506e4beb5eSRussell King if (!pgd_base) 1510c668984SRussell King return; 1520c668984SRussell King 1536e4beb5eSRussell King pgd = pgd_base + pgd_index(0); 1546e4beb5eSRussell King if (pgd_none_or_clear_bad(pgd)) 1556e4beb5eSRussell King goto no_pgd; 1566e4beb5eSRussell King 15784e6ffb2SMike Rapoport p4d = p4d_offset(pgd, 0); 15884e6ffb2SMike Rapoport if (p4d_none_or_clear_bad(p4d)) 15984e6ffb2SMike Rapoport goto no_p4d; 16084e6ffb2SMike Rapoport 16184e6ffb2SMike Rapoport pud = pud_offset(p4d, 0); 162516295e5SRussell King if (pud_none_or_clear_bad(pud)) 163516295e5SRussell King goto no_pud; 164516295e5SRussell King 165516295e5SRussell King pmd = pmd_offset(pud, 0); 1666e4beb5eSRussell King if (pmd_none_or_clear_bad(pmd)) 1676e4beb5eSRussell King goto no_pmd; 1680c668984SRussell King 1690c82d83cSUwe Kleine-König pte = pmd_pgtable(*pmd); 1700c668984SRussell King pmd_clear(pmd); 1715e541973SBenjamin Herrenschmidt pte_free(mm, pte); 172c4812909SKirill A. Shutemov mm_dec_nr_ptes(mm); 1736e4beb5eSRussell King no_pmd: 174516295e5SRussell King pud_clear(pud); 1755e541973SBenjamin Herrenschmidt pmd_free(mm, pmd); 176b30fe6c7SKirill A. Shutemov mm_dec_nr_pmds(mm); 177516295e5SRussell King no_pud: 17884e6ffb2SMike Rapoport p4d_clear(p4d); 179516295e5SRussell King pud_free(mm, pud); 18084e6ffb2SMike Rapoport no_p4d: 18184e6ffb2SMike Rapoport pgd_clear(pgd); 18284e6ffb2SMike Rapoport p4d_free(mm, p4d); 1836e4beb5eSRussell King no_pgd: 184da028779SCatalin Marinas #ifdef CONFIG_ARM_LPAE 185da028779SCatalin Marinas /* 186da028779SCatalin Marinas * Free modules/pkmap or identity pmd tables. 187da028779SCatalin Marinas */ 188da028779SCatalin Marinas for (pgd = pgd_base; pgd < pgd_base + PTRS_PER_PGD; pgd++) { 189da028779SCatalin Marinas if (pgd_none_or_clear_bad(pgd)) 190da028779SCatalin Marinas continue; 191da028779SCatalin Marinas if (pgd_val(*pgd) & L_PGD_SWAPPER) 192da028779SCatalin Marinas continue; 19384e6ffb2SMike Rapoport p4d = p4d_offset(pgd, 0); 19484e6ffb2SMike Rapoport if (p4d_none_or_clear_bad(p4d)) 19584e6ffb2SMike Rapoport continue; 19684e6ffb2SMike Rapoport pud = pud_offset(p4d, 0); 197da028779SCatalin Marinas if (pud_none_or_clear_bad(pud)) 198da028779SCatalin Marinas continue; 199da028779SCatalin Marinas pmd = pmd_offset(pud, 0); 200da028779SCatalin Marinas pud_clear(pud); 201da028779SCatalin Marinas pmd_free(mm, pmd); 202b30fe6c7SKirill A. Shutemov mm_dec_nr_pmds(mm); 20384e6ffb2SMike Rapoport p4d_clear(p4d); 204da028779SCatalin Marinas pud_free(mm, pud); 20584e6ffb2SMike Rapoport mm_dec_nr_puds(mm); 20684e6ffb2SMike Rapoport pgd_clear(pgd); 20784e6ffb2SMike Rapoport p4d_free(mm, p4d); 208da028779SCatalin Marinas } 209da028779SCatalin Marinas #endif 210da028779SCatalin Marinas __pgd_free(pgd_base); 2110c668984SRussell King } 212