xref: /OK3568_Linux_fs/kernel/arch/x86/mm/ident_map.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Helper routines for building identity mapping page tables. This is
4*4882a593Smuzhiyun  * included by both the compressed kernel and the regular kernel.
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
ident_pmd_init(struct x86_mapping_info * info,pmd_t * pmd_page,unsigned long addr,unsigned long end)7*4882a593Smuzhiyun static void ident_pmd_init(struct x86_mapping_info *info, pmd_t *pmd_page,
8*4882a593Smuzhiyun 			   unsigned long addr, unsigned long end)
9*4882a593Smuzhiyun {
10*4882a593Smuzhiyun 	addr &= PMD_MASK;
11*4882a593Smuzhiyun 	for (; addr < end; addr += PMD_SIZE) {
12*4882a593Smuzhiyun 		pmd_t *pmd = pmd_page + pmd_index(addr);
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun 		if (pmd_present(*pmd))
15*4882a593Smuzhiyun 			continue;
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun 		set_pmd(pmd, __pmd((addr - info->offset) | info->page_flag));
18*4882a593Smuzhiyun 	}
19*4882a593Smuzhiyun }
20*4882a593Smuzhiyun 
ident_pud_init(struct x86_mapping_info * info,pud_t * pud_page,unsigned long addr,unsigned long end)21*4882a593Smuzhiyun static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page,
22*4882a593Smuzhiyun 			  unsigned long addr, unsigned long end)
23*4882a593Smuzhiyun {
24*4882a593Smuzhiyun 	unsigned long next;
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun 	for (; addr < end; addr = next) {
27*4882a593Smuzhiyun 		pud_t *pud = pud_page + pud_index(addr);
28*4882a593Smuzhiyun 		pmd_t *pmd;
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun 		next = (addr & PUD_MASK) + PUD_SIZE;
31*4882a593Smuzhiyun 		if (next > end)
32*4882a593Smuzhiyun 			next = end;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 		if (info->direct_gbpages) {
35*4882a593Smuzhiyun 			pud_t pudval;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 			if (pud_present(*pud))
38*4882a593Smuzhiyun 				continue;
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 			addr &= PUD_MASK;
41*4882a593Smuzhiyun 			pudval = __pud((addr - info->offset) | info->page_flag);
42*4882a593Smuzhiyun 			set_pud(pud, pudval);
43*4882a593Smuzhiyun 			continue;
44*4882a593Smuzhiyun 		}
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 		if (pud_present(*pud)) {
47*4882a593Smuzhiyun 			pmd = pmd_offset(pud, 0);
48*4882a593Smuzhiyun 			ident_pmd_init(info, pmd, addr, next);
49*4882a593Smuzhiyun 			continue;
50*4882a593Smuzhiyun 		}
51*4882a593Smuzhiyun 		pmd = (pmd_t *)info->alloc_pgt_page(info->context);
52*4882a593Smuzhiyun 		if (!pmd)
53*4882a593Smuzhiyun 			return -ENOMEM;
54*4882a593Smuzhiyun 		ident_pmd_init(info, pmd, addr, next);
55*4882a593Smuzhiyun 		set_pud(pud, __pud(__pa(pmd) | info->kernpg_flag));
56*4882a593Smuzhiyun 	}
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	return 0;
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun 
ident_p4d_init(struct x86_mapping_info * info,p4d_t * p4d_page,unsigned long addr,unsigned long end)61*4882a593Smuzhiyun static int ident_p4d_init(struct x86_mapping_info *info, p4d_t *p4d_page,
62*4882a593Smuzhiyun 			  unsigned long addr, unsigned long end)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun 	unsigned long next;
65*4882a593Smuzhiyun 	int result;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	for (; addr < end; addr = next) {
68*4882a593Smuzhiyun 		p4d_t *p4d = p4d_page + p4d_index(addr);
69*4882a593Smuzhiyun 		pud_t *pud;
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 		next = (addr & P4D_MASK) + P4D_SIZE;
72*4882a593Smuzhiyun 		if (next > end)
73*4882a593Smuzhiyun 			next = end;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 		if (p4d_present(*p4d)) {
76*4882a593Smuzhiyun 			pud = pud_offset(p4d, 0);
77*4882a593Smuzhiyun 			result = ident_pud_init(info, pud, addr, next);
78*4882a593Smuzhiyun 			if (result)
79*4882a593Smuzhiyun 				return result;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 			continue;
82*4882a593Smuzhiyun 		}
83*4882a593Smuzhiyun 		pud = (pud_t *)info->alloc_pgt_page(info->context);
84*4882a593Smuzhiyun 		if (!pud)
85*4882a593Smuzhiyun 			return -ENOMEM;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 		result = ident_pud_init(info, pud, addr, next);
88*4882a593Smuzhiyun 		if (result)
89*4882a593Smuzhiyun 			return result;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 		set_p4d(p4d, __p4d(__pa(pud) | info->kernpg_flag));
92*4882a593Smuzhiyun 	}
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	return 0;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun 
kernel_ident_mapping_init(struct x86_mapping_info * info,pgd_t * pgd_page,unsigned long pstart,unsigned long pend)97*4882a593Smuzhiyun int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page,
98*4882a593Smuzhiyun 			      unsigned long pstart, unsigned long pend)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	unsigned long addr = pstart + info->offset;
101*4882a593Smuzhiyun 	unsigned long end = pend + info->offset;
102*4882a593Smuzhiyun 	unsigned long next;
103*4882a593Smuzhiyun 	int result;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	/* Set the default pagetable flags if not supplied */
106*4882a593Smuzhiyun 	if (!info->kernpg_flag)
107*4882a593Smuzhiyun 		info->kernpg_flag = _KERNPG_TABLE;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	/* Filter out unsupported __PAGE_KERNEL_* bits: */
110*4882a593Smuzhiyun 	info->kernpg_flag &= __default_kernel_pte_mask;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	for (; addr < end; addr = next) {
113*4882a593Smuzhiyun 		pgd_t *pgd = pgd_page + pgd_index(addr);
114*4882a593Smuzhiyun 		p4d_t *p4d;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 		next = (addr & PGDIR_MASK) + PGDIR_SIZE;
117*4882a593Smuzhiyun 		if (next > end)
118*4882a593Smuzhiyun 			next = end;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 		if (pgd_present(*pgd)) {
121*4882a593Smuzhiyun 			p4d = p4d_offset(pgd, 0);
122*4882a593Smuzhiyun 			result = ident_p4d_init(info, p4d, addr, next);
123*4882a593Smuzhiyun 			if (result)
124*4882a593Smuzhiyun 				return result;
125*4882a593Smuzhiyun 			continue;
126*4882a593Smuzhiyun 		}
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 		p4d = (p4d_t *)info->alloc_pgt_page(info->context);
129*4882a593Smuzhiyun 		if (!p4d)
130*4882a593Smuzhiyun 			return -ENOMEM;
131*4882a593Smuzhiyun 		result = ident_p4d_init(info, p4d, addr, next);
132*4882a593Smuzhiyun 		if (result)
133*4882a593Smuzhiyun 			return result;
134*4882a593Smuzhiyun 		if (pgtable_l5_enabled()) {
135*4882a593Smuzhiyun 			set_pgd(pgd, __pgd(__pa(p4d) | info->kernpg_flag));
136*4882a593Smuzhiyun 		} else {
137*4882a593Smuzhiyun 			/*
138*4882a593Smuzhiyun 			 * With p4d folded, pgd is equal to p4d.
139*4882a593Smuzhiyun 			 * The pgd entry has to point to the pud page table in this case.
140*4882a593Smuzhiyun 			 */
141*4882a593Smuzhiyun 			pud_t *pud = pud_offset(p4d, 0);
142*4882a593Smuzhiyun 			set_pgd(pgd, __pgd(__pa(pud) | info->kernpg_flag));
143*4882a593Smuzhiyun 		}
144*4882a593Smuzhiyun 	}
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	return 0;
147*4882a593Smuzhiyun }
148