LCOV - code coverage report
Current view: top level - arch/arm/mm - pgd.c (source / functions) Hit Total Coverage
Test: Real Lines: 17 27 63.0 %
Date: 2020-10-17 15:46:43 Functions: 0 2 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  *  linux/arch/arm/mm/pgd.c
       4                 :            :  *
       5                 :            :  *  Copyright (C) 1998-2005 Russell King
       6                 :            :  */
       7                 :            : #include <linux/mm.h>
       8                 :            : #include <linux/gfp.h>
       9                 :            : #include <linux/highmem.h>
      10                 :            : #include <linux/slab.h>
      11                 :            : 
      12                 :            : #include <asm/cp15.h>
      13                 :            : #include <asm/pgalloc.h>
      14                 :            : #include <asm/page.h>
      15                 :            : #include <asm/tlbflush.h>
      16                 :            : 
      17                 :            : #include "mm.h"
      18                 :            : 
      19                 :            : #ifdef CONFIG_ARM_LPAE
      20                 :            : #define __pgd_alloc()   kmalloc_array(PTRS_PER_PGD, sizeof(pgd_t), GFP_KERNEL)
      21                 :            : #define __pgd_free(pgd) kfree(pgd)
      22                 :            : #else
      23                 :            : #define __pgd_alloc()   (pgd_t *)__get_free_pages(GFP_KERNEL, 2)
      24                 :            : #define __pgd_free(pgd) free_pages((unsigned long)pgd, 2)
      25                 :            : #endif
      26                 :            : 
      27                 :            : /*
      28                 :            :  * need to get a 16k page for level 1
      29                 :            :  */
      30                 :          3 : pgd_t *pgd_alloc(struct mm_struct *mm)
      31                 :            : {
      32                 :            :         pgd_t *new_pgd, *init_pgd;
      33                 :            :         pud_t *new_pud, *init_pud;
      34                 :            :         pmd_t *new_pmd, *init_pmd;
      35                 :            :         pte_t *new_pte, *init_pte;
      36                 :            : 
      37                 :          3 :         new_pgd = __pgd_alloc();
      38                 :          3 :         if (!new_pgd)
      39                 :            :                 goto no_pgd;
      40                 :            : 
      41                 :          3 :         memset(new_pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
      42                 :            : 
      43                 :            :         /*
      44                 :            :          * Copy over the kernel and IO PGD entries
      45                 :            :          */
      46                 :          3 :         init_pgd = pgd_offset_k(0);
      47                 :          3 :         memcpy(new_pgd + USER_PTRS_PER_PGD, init_pgd + USER_PTRS_PER_PGD,
      48                 :            :                        (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
      49                 :            : 
      50                 :          3 :         clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
      51                 :            : 
      52                 :            : #ifdef CONFIG_ARM_LPAE
      53                 :            :         /*
      54                 :            :          * Allocate PMD table for modules and pkmap mappings.
      55                 :            :          */
      56                 :            :         new_pud = pud_alloc(mm, new_pgd + pgd_index(MODULES_VADDR),
      57                 :            :                             MODULES_VADDR);
      58                 :            :         if (!new_pud)
      59                 :            :                 goto no_pud;
      60                 :            : 
      61                 :            :         new_pmd = pmd_alloc(mm, new_pud, 0);
      62                 :            :         if (!new_pmd)
      63                 :            :                 goto no_pmd;
      64                 :            : #endif
      65                 :            : 
      66                 :          3 :         if (!vectors_high()) {
      67                 :            :                 /*
      68                 :            :                  * On ARM, first page must always be allocated since it
      69                 :            :                  * contains the machine vectors. The vectors are always high
      70                 :            :                  * with LPAE.
      71                 :            :                  */
      72                 :            :                 new_pud = pud_alloc(mm, new_pgd, 0);
      73                 :          0 :                 if (!new_pud)
      74                 :            :                         goto no_pud;
      75                 :            : 
      76                 :            :                 new_pmd = pmd_alloc(mm, new_pud, 0);
      77                 :          0 :                 if (!new_pmd)
      78                 :            :                         goto no_pmd;
      79                 :            : 
      80                 :          0 :                 new_pte = pte_alloc_map(mm, new_pmd, 0);
      81                 :          0 :                 if (!new_pte)
      82                 :            :                         goto no_pte;
      83                 :            : 
      84                 :            : #ifndef CONFIG_ARM_LPAE
      85                 :            :                 /*
      86                 :            :                  * Modify the PTE pointer to have the correct domain.  This
      87                 :            :                  * needs to be the vectors domain to avoid the low vectors
      88                 :            :                  * being unmapped.
      89                 :            :                  */
      90                 :          0 :                 pmd_val(*new_pmd) &= ~PMD_DOMAIN_MASK;
      91                 :          0 :                 pmd_val(*new_pmd) |= PMD_DOMAIN(DOMAIN_VECTORS);
      92                 :            : #endif
      93                 :            : 
      94                 :            :                 init_pud = pud_offset(init_pgd, 0);
      95                 :            :                 init_pmd = pmd_offset(init_pud, 0);
      96                 :          0 :                 init_pte = pte_offset_map(init_pmd, 0);
      97                 :          0 :                 set_pte_ext(new_pte + 0, init_pte[0], 0);
      98                 :          0 :                 set_pte_ext(new_pte + 1, init_pte[1], 0);
      99                 :            :                 pte_unmap(init_pte);
     100                 :            :                 pte_unmap(new_pte);
     101                 :            :         }
     102                 :            : 
     103                 :          3 :         return new_pgd;
     104                 :            : 
     105                 :            : no_pte:
     106                 :            :         pmd_free(mm, new_pmd);
     107                 :            :         mm_dec_nr_pmds(mm);
     108                 :            : no_pmd:
     109                 :            :         pud_free(mm, new_pud);
     110                 :            : no_pud:
     111                 :          0 :         __pgd_free(new_pgd);
     112                 :            : no_pgd:
     113                 :            :         return NULL;
     114                 :            : }
     115                 :            : 
     116                 :          3 : void pgd_free(struct mm_struct *mm, pgd_t *pgd_base)
     117                 :            : {
     118                 :            :         pgd_t *pgd;
     119                 :            :         pud_t *pud;
     120                 :            :         pmd_t *pmd;
     121                 :            :         pgtable_t pte;
     122                 :            : 
     123                 :          3 :         if (!pgd_base)
     124                 :          3 :                 return;
     125                 :            : 
     126                 :            :         pgd = pgd_base + pgd_index(0);
     127                 :            :         if (pgd_none_or_clear_bad(pgd))
     128                 :            :                 goto no_pgd;
     129                 :            : 
     130                 :            :         pud = pud_offset(pgd, 0);
     131                 :            :         if (pud_none_or_clear_bad(pud))
     132                 :            :                 goto no_pud;
     133                 :            : 
     134                 :            :         pmd = pmd_offset(pud, 0);
     135                 :          3 :         if (pmd_none_or_clear_bad(pmd))
     136                 :            :                 goto no_pmd;
     137                 :            : 
     138                 :          3 :         pte = pmd_pgtable(*pmd);
     139                 :          3 :         pmd_clear(pmd);
     140                 :          3 :         pte_free(mm, pte);
     141                 :            :         mm_dec_nr_ptes(mm);
     142                 :            : no_pmd:
     143                 :            :         pud_clear(pud);
     144                 :            :         pmd_free(mm, pmd);
     145                 :            :         mm_dec_nr_pmds(mm);
     146                 :            : no_pud:
     147                 :            :         pgd_clear(pgd);
     148                 :            :         pud_free(mm, pud);
     149                 :            : no_pgd:
     150                 :            : #ifdef CONFIG_ARM_LPAE
     151                 :            :         /*
     152                 :            :          * Free modules/pkmap or identity pmd tables.
     153                 :            :          */
     154                 :            :         for (pgd = pgd_base; pgd < pgd_base + PTRS_PER_PGD; pgd++) {
     155                 :            :                 if (pgd_none_or_clear_bad(pgd))
     156                 :            :                         continue;
     157                 :            :                 if (pgd_val(*pgd) & L_PGD_SWAPPER)
     158                 :            :                         continue;
     159                 :            :                 pud = pud_offset(pgd, 0);
     160                 :            :                 if (pud_none_or_clear_bad(pud))
     161                 :            :                         continue;
     162                 :            :                 pmd = pmd_offset(pud, 0);
     163                 :            :                 pud_clear(pud);
     164                 :            :                 pmd_free(mm, pmd);
     165                 :            :                 mm_dec_nr_pmds(mm);
     166                 :            :                 pgd_clear(pgd);
     167                 :            :                 pud_free(mm, pud);
     168                 :            :         }
     169                 :            : #endif
     170                 :          3 :         __pgd_free(pgd_base);
     171                 :            : }
    

Generated by: LCOV version 1.14