1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2020 Loongson Technology Corporation Limited
4 */
5 #include <linux/export.h>
6 #include <linux/init.h>
7 #include <linux/mm.h>
8 #include <asm/fixmap.h>
9 #include <asm/pgtable.h>
10 #include <asm/pgalloc.h>
11 #include <asm/tlbflush.h>
12
pgd_init(unsigned long page)13 void pgd_init(unsigned long page)
14 {
15 unsigned long *p, *end;
16 unsigned long entry;
17
18 #if !defined(__PAGETABLE_PUD_FOLDED)
19 entry = (unsigned long)invalid_pud_table;
20 #elif !defined(__PAGETABLE_PMD_FOLDED)
21 entry = (unsigned long)invalid_pmd_table;
22 #else
23 entry = (unsigned long)invalid_pte_table;
24 #endif
25
26 p = (unsigned long *) page;
27 end = p + PTRS_PER_PGD;
28
29 do {
30 p[0] = entry;
31 p[1] = entry;
32 p[2] = entry;
33 p[3] = entry;
34 p[4] = entry;
35 p += 8;
36 p[-3] = entry;
37 p[-2] = entry;
38 p[-1] = entry;
39 } while (p != end);
40 }
41 EXPORT_SYMBOL_GPL(pgd_init);
42
43 #ifndef __PAGETABLE_PMD_FOLDED
pmd_init(unsigned long addr, unsigned long pagetable)44 void pmd_init(unsigned long addr, unsigned long pagetable)
45 {
46 unsigned long *p, *end;
47
48 p = (unsigned long *) addr;
49 end = p + PTRS_PER_PMD;
50
51 do {
52 p[0] = pagetable;
53 p[1] = pagetable;
54 p[2] = pagetable;
55 p[3] = pagetable;
56 p[4] = pagetable;
57 p += 8;
58 p[-3] = pagetable;
59 p[-2] = pagetable;
60 p[-1] = pagetable;
61 } while (p != end);
62 }
63 EXPORT_SYMBOL_GPL(pmd_init);
64 #endif
65
66 #ifndef __PAGETABLE_PUD_FOLDED
pud_init(unsigned long addr, unsigned long pagetable)67 void pud_init(unsigned long addr, unsigned long pagetable)
68 {
69 unsigned long *p, *end;
70
71 p = (unsigned long *)addr;
72 end = p + PTRS_PER_PUD;
73
74 do {
75 p[0] = pagetable;
76 p[1] = pagetable;
77 p[2] = pagetable;
78 p[3] = pagetable;
79 p[4] = pagetable;
80 p += 8;
81 p[-3] = pagetable;
82 p[-2] = pagetable;
83 p[-1] = pagetable;
84 } while (p != end);
85 }
86 #endif
87
mk_pmd(struct page *page, pgprot_t prot)88 pmd_t mk_pmd(struct page *page, pgprot_t prot)
89 {
90 pmd_t pmd;
91
92 pmd_val(pmd) = (page_to_pfn(page) << _PFN_SHIFT) | pgprot_val(prot);
93
94 return pmd;
95 }
96
set_pmd_at(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp, pmd_t pmd)97 void set_pmd_at(struct mm_struct *mm, unsigned long addr,
98 pmd_t *pmdp, pmd_t pmd)
99 {
100 *pmdp = pmd;
101 flush_tlb_all();
102 }
103
pagetable_init(void)104 void __init pagetable_init(void)
105 {
106 unsigned long vaddr;
107
108 /* Initialize the entire pgd. */
109 pgd_init((unsigned long)swapper_pg_dir);
110 pgd_init((unsigned long)invalid_pg_dir);
111 #ifndef __PAGETABLE_PUD_FOLDED
112 pud_init((unsigned long)invalid_pud_table, (unsigned long)invalid_pmd_table);
113 #endif
114 #ifndef __PAGETABLE_PMD_FOLDED
115 pmd_init((unsigned long)invalid_pmd_table, (unsigned long)invalid_pte_table);
116 #endif
117 /*
118 * Fixed mappings:
119 */
120 vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
121 }
122