2017-10-24 15:05:47 +08:00
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2005-2017 Andes Technology Corporation
# include <linux/init_task.h>
2020-08-06 23:22:47 -07:00
# define __HAVE_ARCH_PGD_FREE
2017-10-24 15:05:47 +08:00
# include <asm/pgalloc.h>
# define FIRST_KERNEL_PGD_NR (USER_PTRS_PER_PGD)
/*
* need to get a page for level 1
*/
pgd_t * pgd_alloc ( struct mm_struct * mm )
{
pgd_t * new_pgd , * init_pgd ;
int i ;
new_pgd = ( pgd_t * ) __get_free_pages ( GFP_KERNEL , 0 ) ;
if ( ! new_pgd )
return NULL ;
for ( i = 0 ; i < PTRS_PER_PGD ; i + + ) {
( * new_pgd ) = 1 ;
new_pgd + + ;
}
new_pgd - = PTRS_PER_PGD ;
init_pgd = pgd_offset_k ( 0 ) ;
memcpy ( new_pgd + FIRST_KERNEL_PGD_NR , init_pgd + FIRST_KERNEL_PGD_NR ,
( PTRS_PER_PGD - FIRST_KERNEL_PGD_NR ) * sizeof ( pgd_t ) ) ;
cpu_dcache_wb_range ( ( unsigned long ) new_pgd ,
( unsigned long ) new_pgd +
PTRS_PER_PGD * sizeof ( pgd_t ) ) ;
2020-12-14 19:07:17 -08:00
inc_lruvec_page_state ( virt_to_page ( ( unsigned long * ) new_pgd ) ,
NR_PAGETABLE ) ;
2017-10-24 15:05:47 +08:00
return new_pgd ;
}
void pgd_free ( struct mm_struct * mm , pgd_t * pgd )
{
pmd_t * pmd ;
struct page * pte ;
if ( ! pgd )
return ;
pmd = ( pmd_t * ) pgd ;
if ( pmd_none ( * pmd ) )
goto free ;
if ( pmd_bad ( * pmd ) ) {
pmd_ERROR ( * pmd ) ;
pmd_clear ( pmd ) ;
goto free ;
}
pte = pmd_page ( * pmd ) ;
pmd_clear ( pmd ) ;
2020-12-14 19:07:17 -08:00
dec_lruvec_page_state ( virt_to_page ( ( unsigned long * ) pgd ) , NR_PAGETABLE ) ;
2017-10-24 15:05:47 +08:00
pte_free ( mm , pte ) ;
mm_dec_nr_ptes ( mm ) ;
pmd_free ( mm , pmd ) ;
free :
free_pages ( ( unsigned long ) pgd , 0 ) ;
}
/*
* In order to soft - boot , we need to insert a 1 : 1 mapping in place of
* the user - mode pages . This will then ensure that we have predictable
* results when turning the mmu off
*/
void setup_mm_for_reboot ( char mode )
{
unsigned long pmdval ;
pgd_t * pgd ;
2019-12-04 16:54:08 -08:00
p4d_t * p4d ;
pud_t * pud ;
2017-10-24 15:05:47 +08:00
pmd_t * pmd ;
int i ;
if ( current - > mm & & current - > mm - > pgd )
pgd = current - > mm - > pgd ;
else
pgd = init_mm . pgd ;
for ( i = 0 ; i < USER_PTRS_PER_PGD ; i + + ) {
pmdval = ( i < < PGDIR_SHIFT ) ;
2019-12-04 16:54:08 -08:00
p4d = p4d_offset ( pgd , i < < PGDIR_SHIFT ) ;
pud = pud_offset ( p4d , i < < PGDIR_SHIFT ) ;
pmd = pmd_offset ( pud + i , i < < PGDIR_SHIFT ) ;
2017-10-24 15:05:47 +08:00
set_pmd ( pmd , __pmd ( pmdval ) ) ;
}
}