• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2005-2017 Andes Technology Corporation
3 
4 #include <linux/init_task.h>
5 #include <asm/pgalloc.h>
6 
7 #define FIRST_KERNEL_PGD_NR	(USER_PTRS_PER_PGD)
8 
9 /*
10  * need to get a page for level 1
11  */
12 
pgd_alloc(struct mm_struct * mm)13 pgd_t *pgd_alloc(struct mm_struct *mm)
14 {
15 	pgd_t *new_pgd, *init_pgd;
16 	int i;
17 
18 	new_pgd = (pgd_t *) __get_free_pages(GFP_KERNEL, 0);
19 	if (!new_pgd)
20 		return NULL;
21 	for (i = 0; i < PTRS_PER_PGD; i++) {
22 		(*new_pgd) = 1;
23 		new_pgd++;
24 	}
25 	new_pgd -= PTRS_PER_PGD;
26 
27 	init_pgd = pgd_offset_k(0);
28 
29 	memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
30 	       (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
31 
32 	cpu_dcache_wb_range((unsigned long)new_pgd,
33 			    (unsigned long)new_pgd +
34 			    PTRS_PER_PGD * sizeof(pgd_t));
35 	inc_zone_page_state(virt_to_page((unsigned long *)new_pgd),
36 			    NR_PAGETABLE);
37 
38 	return new_pgd;
39 }
40 
pgd_free(struct mm_struct * mm,pgd_t * pgd)41 void pgd_free(struct mm_struct *mm, pgd_t * pgd)
42 {
43 	pmd_t *pmd;
44 	struct page *pte;
45 
46 	if (!pgd)
47 		return;
48 
49 	pmd = (pmd_t *) pgd;
50 	if (pmd_none(*pmd))
51 		goto free;
52 	if (pmd_bad(*pmd)) {
53 		pmd_ERROR(*pmd);
54 		pmd_clear(pmd);
55 		goto free;
56 	}
57 
58 	pte = pmd_page(*pmd);
59 	pmd_clear(pmd);
60 	dec_zone_page_state(virt_to_page((unsigned long *)pgd), NR_PAGETABLE);
61 	pte_free(mm, pte);
62 	mm_dec_nr_ptes(mm);
63 	pmd_free(mm, pmd);
64 free:
65 	free_pages((unsigned long)pgd, 0);
66 }
67 
68 /*
69  * In order to soft-boot, we need to insert a 1:1 mapping in place of
70  * the user-mode pages.  This will then ensure that we have predictable
71  * results when turning the mmu off
72  */
setup_mm_for_reboot(char mode)73 void setup_mm_for_reboot(char mode)
74 {
75 	unsigned long pmdval;
76 	pgd_t *pgd;
77 	pmd_t *pmd;
78 	int i;
79 
80 	if (current->mm && current->mm->pgd)
81 		pgd = current->mm->pgd;
82 	else
83 		pgd = init_mm.pgd;
84 
85 	for (i = 0; i < USER_PTRS_PER_PGD; i++) {
86 		pmdval = (i << PGDIR_SHIFT);
87 		pmd = pmd_offset(pgd + i, i << PGDIR_SHIFT);
88 		set_pmd(pmd, __pmd(pmdval));
89 	}
90 }
91