LCOV - code coverage report
Current view: top level - arch/arm/mm - pgd.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 14 26 53.8 %
Date: 2014-04-16 Functions: 2 2 100.0 %
Branches: 5 17 29.4 %

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

Generated by: LCOV version 1.9