xref: /openbmc/linux/arch/arm64/mm/mmu.c (revision af86e5974d3069bd26ebcf7c046c6e59726acaaa)
1c1cc1552SCatalin Marinas /*
2c1cc1552SCatalin Marinas  * Based on arch/arm/mm/mmu.c
3c1cc1552SCatalin Marinas  *
4c1cc1552SCatalin Marinas  * Copyright (C) 1995-2005 Russell King
5c1cc1552SCatalin Marinas  * Copyright (C) 2012 ARM Ltd.
6c1cc1552SCatalin Marinas  *
7c1cc1552SCatalin Marinas  * This program is free software; you can redistribute it and/or modify
8c1cc1552SCatalin Marinas  * it under the terms of the GNU General Public License version 2 as
9c1cc1552SCatalin Marinas  * published by the Free Software Foundation.
10c1cc1552SCatalin Marinas  *
11c1cc1552SCatalin Marinas  * This program is distributed in the hope that it will be useful,
12c1cc1552SCatalin Marinas  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13c1cc1552SCatalin Marinas  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14c1cc1552SCatalin Marinas  * GNU General Public License for more details.
15c1cc1552SCatalin Marinas  *
16c1cc1552SCatalin Marinas  * You should have received a copy of the GNU General Public License
17c1cc1552SCatalin Marinas  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18c1cc1552SCatalin Marinas  */
19c1cc1552SCatalin Marinas 
20c1cc1552SCatalin Marinas #include <linux/export.h>
21c1cc1552SCatalin Marinas #include <linux/kernel.h>
22c1cc1552SCatalin Marinas #include <linux/errno.h>
23c1cc1552SCatalin Marinas #include <linux/init.h>
24c1cc1552SCatalin Marinas #include <linux/mman.h>
25c1cc1552SCatalin Marinas #include <linux/nodemask.h>
26c1cc1552SCatalin Marinas #include <linux/memblock.h>
27c1cc1552SCatalin Marinas #include <linux/fs.h>
282475ff9dSCatalin Marinas #include <linux/io.h>
29c1cc1552SCatalin Marinas 
30c1cc1552SCatalin Marinas #include <asm/cputype.h>
31*af86e597SLaura Abbott #include <asm/fixmap.h>
32c1cc1552SCatalin Marinas #include <asm/sections.h>
33c1cc1552SCatalin Marinas #include <asm/setup.h>
34c1cc1552SCatalin Marinas #include <asm/sizes.h>
35c1cc1552SCatalin Marinas #include <asm/tlb.h>
36c79b954bSJungseok Lee #include <asm/memblock.h>
37c1cc1552SCatalin Marinas #include <asm/mmu_context.h>
38c1cc1552SCatalin Marinas 
39c1cc1552SCatalin Marinas #include "mm.h"
40c1cc1552SCatalin Marinas 
41c1cc1552SCatalin Marinas /*
42c1cc1552SCatalin Marinas  * Empty_zero_page is a special page that is used for zero-initialized data
43c1cc1552SCatalin Marinas  * and COW.
44c1cc1552SCatalin Marinas  */
45c1cc1552SCatalin Marinas struct page *empty_zero_page;
46c1cc1552SCatalin Marinas EXPORT_SYMBOL(empty_zero_page);
47c1cc1552SCatalin Marinas 
48c1cc1552SCatalin Marinas struct cachepolicy {
49c1cc1552SCatalin Marinas 	const char	policy[16];
50c1cc1552SCatalin Marinas 	u64		mair;
51c1cc1552SCatalin Marinas 	u64		tcr;
52c1cc1552SCatalin Marinas };
53c1cc1552SCatalin Marinas 
54c1cc1552SCatalin Marinas static struct cachepolicy cache_policies[] __initdata = {
55c1cc1552SCatalin Marinas 	{
56c1cc1552SCatalin Marinas 		.policy		= "uncached",
57c1cc1552SCatalin Marinas 		.mair		= 0x44,			/* inner, outer non-cacheable */
58c1cc1552SCatalin Marinas 		.tcr		= TCR_IRGN_NC | TCR_ORGN_NC,
59c1cc1552SCatalin Marinas 	}, {
60c1cc1552SCatalin Marinas 		.policy		= "writethrough",
61c1cc1552SCatalin Marinas 		.mair		= 0xaa,			/* inner, outer write-through, read-allocate */
62c1cc1552SCatalin Marinas 		.tcr		= TCR_IRGN_WT | TCR_ORGN_WT,
63c1cc1552SCatalin Marinas 	}, {
64c1cc1552SCatalin Marinas 		.policy		= "writeback",
65c1cc1552SCatalin Marinas 		.mair		= 0xee,			/* inner, outer write-back, read-allocate */
66c1cc1552SCatalin Marinas 		.tcr		= TCR_IRGN_WBnWA | TCR_ORGN_WBnWA,
67c1cc1552SCatalin Marinas 	}
68c1cc1552SCatalin Marinas };
69c1cc1552SCatalin Marinas 
70c1cc1552SCatalin Marinas /*
71c1cc1552SCatalin Marinas  * These are useful for identifying cache coherency problems by allowing the
72c1cc1552SCatalin Marinas  * cache or the cache and writebuffer to be turned off. It changes the Normal
73c1cc1552SCatalin Marinas  * memory caching attributes in the MAIR_EL1 register.
74c1cc1552SCatalin Marinas  */
75c1cc1552SCatalin Marinas static int __init early_cachepolicy(char *p)
76c1cc1552SCatalin Marinas {
77c1cc1552SCatalin Marinas 	int i;
78c1cc1552SCatalin Marinas 	u64 tmp;
79c1cc1552SCatalin Marinas 
80c1cc1552SCatalin Marinas 	for (i = 0; i < ARRAY_SIZE(cache_policies); i++) {
81c1cc1552SCatalin Marinas 		int len = strlen(cache_policies[i].policy);
82c1cc1552SCatalin Marinas 
83c1cc1552SCatalin Marinas 		if (memcmp(p, cache_policies[i].policy, len) == 0)
84c1cc1552SCatalin Marinas 			break;
85c1cc1552SCatalin Marinas 	}
86c1cc1552SCatalin Marinas 	if (i == ARRAY_SIZE(cache_policies)) {
87c1cc1552SCatalin Marinas 		pr_err("ERROR: unknown or unsupported cache policy: %s\n", p);
88c1cc1552SCatalin Marinas 		return 0;
89c1cc1552SCatalin Marinas 	}
90c1cc1552SCatalin Marinas 
91c1cc1552SCatalin Marinas 	flush_cache_all();
92c1cc1552SCatalin Marinas 
93c1cc1552SCatalin Marinas 	/*
94c1cc1552SCatalin Marinas 	 * Modify MT_NORMAL attributes in MAIR_EL1.
95c1cc1552SCatalin Marinas 	 */
96c1cc1552SCatalin Marinas 	asm volatile(
97c1cc1552SCatalin Marinas 	"	mrs	%0, mair_el1\n"
98fe184066SMark Charlebois 	"	bfi	%0, %1, %2, #8\n"
99c1cc1552SCatalin Marinas 	"	msr	mair_el1, %0\n"
100c1cc1552SCatalin Marinas 	"	isb\n"
101c1cc1552SCatalin Marinas 	: "=&r" (tmp)
102c1cc1552SCatalin Marinas 	: "r" (cache_policies[i].mair), "i" (MT_NORMAL * 8));
103c1cc1552SCatalin Marinas 
104c1cc1552SCatalin Marinas 	/*
105c1cc1552SCatalin Marinas 	 * Modify TCR PTW cacheability attributes.
106c1cc1552SCatalin Marinas 	 */
107c1cc1552SCatalin Marinas 	asm volatile(
108c1cc1552SCatalin Marinas 	"	mrs	%0, tcr_el1\n"
109c1cc1552SCatalin Marinas 	"	bic	%0, %0, %2\n"
110c1cc1552SCatalin Marinas 	"	orr	%0, %0, %1\n"
111c1cc1552SCatalin Marinas 	"	msr	tcr_el1, %0\n"
112c1cc1552SCatalin Marinas 	"	isb\n"
113c1cc1552SCatalin Marinas 	: "=&r" (tmp)
114c1cc1552SCatalin Marinas 	: "r" (cache_policies[i].tcr), "r" (TCR_IRGN_MASK | TCR_ORGN_MASK));
115c1cc1552SCatalin Marinas 
116c1cc1552SCatalin Marinas 	flush_cache_all();
117c1cc1552SCatalin Marinas 
118c1cc1552SCatalin Marinas 	return 0;
119c1cc1552SCatalin Marinas }
120c1cc1552SCatalin Marinas early_param("cachepolicy", early_cachepolicy);
121c1cc1552SCatalin Marinas 
122c1cc1552SCatalin Marinas pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
123c1cc1552SCatalin Marinas 			      unsigned long size, pgprot_t vma_prot)
124c1cc1552SCatalin Marinas {
125c1cc1552SCatalin Marinas 	if (!pfn_valid(pfn))
126c1cc1552SCatalin Marinas 		return pgprot_noncached(vma_prot);
127c1cc1552SCatalin Marinas 	else if (file->f_flags & O_SYNC)
128c1cc1552SCatalin Marinas 		return pgprot_writecombine(vma_prot);
129c1cc1552SCatalin Marinas 	return vma_prot;
130c1cc1552SCatalin Marinas }
131c1cc1552SCatalin Marinas EXPORT_SYMBOL(phys_mem_access_prot);
132c1cc1552SCatalin Marinas 
133c1cc1552SCatalin Marinas static void __init *early_alloc(unsigned long sz)
134c1cc1552SCatalin Marinas {
135c1cc1552SCatalin Marinas 	void *ptr = __va(memblock_alloc(sz, sz));
136c1cc1552SCatalin Marinas 	memset(ptr, 0, sz);
137c1cc1552SCatalin Marinas 	return ptr;
138c1cc1552SCatalin Marinas }
139c1cc1552SCatalin Marinas 
140c1cc1552SCatalin Marinas static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
141d7ecbddfSMark Salter 				  unsigned long end, unsigned long pfn,
142d7ecbddfSMark Salter 				  pgprot_t prot)
143c1cc1552SCatalin Marinas {
144c1cc1552SCatalin Marinas 	pte_t *pte;
145c1cc1552SCatalin Marinas 
146c1cc1552SCatalin Marinas 	if (pmd_none(*pmd)) {
147c1cc1552SCatalin Marinas 		pte = early_alloc(PTRS_PER_PTE * sizeof(pte_t));
148c1cc1552SCatalin Marinas 		__pmd_populate(pmd, __pa(pte), PMD_TYPE_TABLE);
149c1cc1552SCatalin Marinas 	}
150c1cc1552SCatalin Marinas 	BUG_ON(pmd_bad(*pmd));
151c1cc1552SCatalin Marinas 
152c1cc1552SCatalin Marinas 	pte = pte_offset_kernel(pmd, addr);
153c1cc1552SCatalin Marinas 	do {
154d7ecbddfSMark Salter 		set_pte(pte, pfn_pte(pfn, prot));
155c1cc1552SCatalin Marinas 		pfn++;
156c1cc1552SCatalin Marinas 	} while (pte++, addr += PAGE_SIZE, addr != end);
157c1cc1552SCatalin Marinas }
158c1cc1552SCatalin Marinas 
159c1cc1552SCatalin Marinas static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
160d7ecbddfSMark Salter 				  unsigned long end, phys_addr_t phys,
161d7ecbddfSMark Salter 				  int map_io)
162c1cc1552SCatalin Marinas {
163c1cc1552SCatalin Marinas 	pmd_t *pmd;
164c1cc1552SCatalin Marinas 	unsigned long next;
165d7ecbddfSMark Salter 	pmdval_t prot_sect;
166d7ecbddfSMark Salter 	pgprot_t prot_pte;
167d7ecbddfSMark Salter 
168d7ecbddfSMark Salter 	if (map_io) {
169cc07aabcSLinus Torvalds 		prot_sect = PROT_SECT_DEVICE_nGnRE;
170d7ecbddfSMark Salter 		prot_pte = __pgprot(PROT_DEVICE_nGnRE);
171d7ecbddfSMark Salter 	} else {
172cc07aabcSLinus Torvalds 		prot_sect = PROT_SECT_NORMAL_EXEC;
173d7ecbddfSMark Salter 		prot_pte = PAGE_KERNEL_EXEC;
174d7ecbddfSMark Salter 	}
175c1cc1552SCatalin Marinas 
176c1cc1552SCatalin Marinas 	/*
177c1cc1552SCatalin Marinas 	 * Check for initial section mappings in the pgd/pud and remove them.
178c1cc1552SCatalin Marinas 	 */
179c1cc1552SCatalin Marinas 	if (pud_none(*pud) || pud_bad(*pud)) {
180c1cc1552SCatalin Marinas 		pmd = early_alloc(PTRS_PER_PMD * sizeof(pmd_t));
181c1cc1552SCatalin Marinas 		pud_populate(&init_mm, pud, pmd);
182c1cc1552SCatalin Marinas 	}
183c1cc1552SCatalin Marinas 
184c1cc1552SCatalin Marinas 	pmd = pmd_offset(pud, addr);
185c1cc1552SCatalin Marinas 	do {
186c1cc1552SCatalin Marinas 		next = pmd_addr_end(addr, end);
187c1cc1552SCatalin Marinas 		/* try section mapping first */
188a55f9929SCatalin Marinas 		if (((addr | next | phys) & ~SECTION_MASK) == 0) {
189a55f9929SCatalin Marinas 			pmd_t old_pmd =*pmd;
190d7ecbddfSMark Salter 			set_pmd(pmd, __pmd(phys | prot_sect));
191a55f9929SCatalin Marinas 			/*
192a55f9929SCatalin Marinas 			 * Check for previous table entries created during
193a55f9929SCatalin Marinas 			 * boot (__create_page_tables) and flush them.
194a55f9929SCatalin Marinas 			 */
195a55f9929SCatalin Marinas 			if (!pmd_none(old_pmd))
196a55f9929SCatalin Marinas 				flush_tlb_all();
197a55f9929SCatalin Marinas 		} else {
198d7ecbddfSMark Salter 			alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys),
199d7ecbddfSMark Salter 				       prot_pte);
200a55f9929SCatalin Marinas 		}
201c1cc1552SCatalin Marinas 		phys += next - addr;
202c1cc1552SCatalin Marinas 	} while (pmd++, addr = next, addr != end);
203c1cc1552SCatalin Marinas }
204c1cc1552SCatalin Marinas 
205c1cc1552SCatalin Marinas static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
2064ee20980SMin-Hua Chen 				  unsigned long end, phys_addr_t phys,
207d7ecbddfSMark Salter 				  int map_io)
208c1cc1552SCatalin Marinas {
209c79b954bSJungseok Lee 	pud_t *pud;
210c1cc1552SCatalin Marinas 	unsigned long next;
211c1cc1552SCatalin Marinas 
212c79b954bSJungseok Lee 	if (pgd_none(*pgd)) {
213c79b954bSJungseok Lee 		pud = early_alloc(PTRS_PER_PUD * sizeof(pud_t));
214c79b954bSJungseok Lee 		pgd_populate(&init_mm, pgd, pud);
215c79b954bSJungseok Lee 	}
216c79b954bSJungseok Lee 	BUG_ON(pgd_bad(*pgd));
217c79b954bSJungseok Lee 
218c79b954bSJungseok Lee 	pud = pud_offset(pgd, addr);
219c1cc1552SCatalin Marinas 	do {
220c1cc1552SCatalin Marinas 		next = pud_addr_end(addr, end);
221206a2a73SSteve Capper 
222206a2a73SSteve Capper 		/*
223206a2a73SSteve Capper 		 * For 4K granule only, attempt to put down a 1GB block
224206a2a73SSteve Capper 		 */
225cc07aabcSLinus Torvalds 		if (!map_io && (PAGE_SHIFT == 12) &&
226206a2a73SSteve Capper 		    ((addr | next | phys) & ~PUD_MASK) == 0) {
227206a2a73SSteve Capper 			pud_t old_pud = *pud;
228206a2a73SSteve Capper 			set_pud(pud, __pud(phys | PROT_SECT_NORMAL_EXEC));
229206a2a73SSteve Capper 
230206a2a73SSteve Capper 			/*
231206a2a73SSteve Capper 			 * If we have an old value for a pud, it will
232206a2a73SSteve Capper 			 * be pointing to a pmd table that we no longer
233206a2a73SSteve Capper 			 * need (from swapper_pg_dir).
234206a2a73SSteve Capper 			 *
235206a2a73SSteve Capper 			 * Look up the old pmd table and free it.
236206a2a73SSteve Capper 			 */
237206a2a73SSteve Capper 			if (!pud_none(old_pud)) {
238206a2a73SSteve Capper 				phys_addr_t table = __pa(pmd_offset(&old_pud, 0));
239206a2a73SSteve Capper 				memblock_free(table, PAGE_SIZE);
240206a2a73SSteve Capper 				flush_tlb_all();
241206a2a73SSteve Capper 			}
242206a2a73SSteve Capper 		} else {
243d7ecbddfSMark Salter 			alloc_init_pmd(pud, addr, next, phys, map_io);
244206a2a73SSteve Capper 		}
245c1cc1552SCatalin Marinas 		phys += next - addr;
246c1cc1552SCatalin Marinas 	} while (pud++, addr = next, addr != end);
247c1cc1552SCatalin Marinas }
248c1cc1552SCatalin Marinas 
249c1cc1552SCatalin Marinas /*
250c1cc1552SCatalin Marinas  * Create the page directory entries and any necessary page tables for the
251c1cc1552SCatalin Marinas  * mapping specified by 'md'.
252c1cc1552SCatalin Marinas  */
253d7ecbddfSMark Salter static void __init __create_mapping(pgd_t *pgd, phys_addr_t phys,
254d7ecbddfSMark Salter 				    unsigned long virt, phys_addr_t size,
255d7ecbddfSMark Salter 				    int map_io)
256c1cc1552SCatalin Marinas {
257c1cc1552SCatalin Marinas 	unsigned long addr, length, end, next;
258c1cc1552SCatalin Marinas 
259c1cc1552SCatalin Marinas 	addr = virt & PAGE_MASK;
260c1cc1552SCatalin Marinas 	length = PAGE_ALIGN(size + (virt & ~PAGE_MASK));
261c1cc1552SCatalin Marinas 
262c1cc1552SCatalin Marinas 	end = addr + length;
263c1cc1552SCatalin Marinas 	do {
264c1cc1552SCatalin Marinas 		next = pgd_addr_end(addr, end);
265d7ecbddfSMark Salter 		alloc_init_pud(pgd, addr, next, phys, map_io);
266c1cc1552SCatalin Marinas 		phys += next - addr;
267c1cc1552SCatalin Marinas 	} while (pgd++, addr = next, addr != end);
268c1cc1552SCatalin Marinas }
269c1cc1552SCatalin Marinas 
270d7ecbddfSMark Salter static void __init create_mapping(phys_addr_t phys, unsigned long virt,
271d7ecbddfSMark Salter 				  phys_addr_t size)
272d7ecbddfSMark Salter {
273d7ecbddfSMark Salter 	if (virt < VMALLOC_START) {
274d7ecbddfSMark Salter 		pr_warn("BUG: not creating mapping for %pa at 0x%016lx - outside kernel range\n",
275d7ecbddfSMark Salter 			&phys, virt);
276d7ecbddfSMark Salter 		return;
277d7ecbddfSMark Salter 	}
278d7ecbddfSMark Salter 	__create_mapping(pgd_offset_k(virt & PAGE_MASK), phys, virt, size, 0);
279d7ecbddfSMark Salter }
280d7ecbddfSMark Salter 
281d7ecbddfSMark Salter void __init create_id_mapping(phys_addr_t addr, phys_addr_t size, int map_io)
282d7ecbddfSMark Salter {
283d7ecbddfSMark Salter 	if ((addr >> PGDIR_SHIFT) >= ARRAY_SIZE(idmap_pg_dir)) {
284d7ecbddfSMark Salter 		pr_warn("BUG: not creating id mapping for %pa\n", &addr);
285d7ecbddfSMark Salter 		return;
286d7ecbddfSMark Salter 	}
287d7ecbddfSMark Salter 	__create_mapping(&idmap_pg_dir[pgd_index(addr)],
288d7ecbddfSMark Salter 			 addr, addr, size, map_io);
289d7ecbddfSMark Salter }
290d7ecbddfSMark Salter 
291c1cc1552SCatalin Marinas static void __init map_mem(void)
292c1cc1552SCatalin Marinas {
293c1cc1552SCatalin Marinas 	struct memblock_region *reg;
294e25208f7SCatalin Marinas 	phys_addr_t limit;
295c1cc1552SCatalin Marinas 
296f6bc87c3SSteve Capper 	/*
297f6bc87c3SSteve Capper 	 * Temporarily limit the memblock range. We need to do this as
298f6bc87c3SSteve Capper 	 * create_mapping requires puds, pmds and ptes to be allocated from
299f6bc87c3SSteve Capper 	 * memory addressable from the initial direct kernel mapping.
300f6bc87c3SSteve Capper 	 *
3013dec0fe4SCatalin Marinas 	 * The initial direct kernel mapping, located at swapper_pg_dir, gives
3023dec0fe4SCatalin Marinas 	 * us PUD_SIZE (4K pages) or PMD_SIZE (64K pages) memory starting from
3033dec0fe4SCatalin Marinas 	 * PHYS_OFFSET (which must be aligned to 2MB as per
3043dec0fe4SCatalin Marinas 	 * Documentation/arm64/booting.txt).
305f6bc87c3SSteve Capper 	 */
3063dec0fe4SCatalin Marinas 	if (IS_ENABLED(CONFIG_ARM64_64K_PAGES))
3073dec0fe4SCatalin Marinas 		limit = PHYS_OFFSET + PMD_SIZE;
3083dec0fe4SCatalin Marinas 	else
309c79b954bSJungseok Lee 		limit = PHYS_OFFSET + PUD_SIZE;
310e25208f7SCatalin Marinas 	memblock_set_current_limit(limit);
311f6bc87c3SSteve Capper 
312c1cc1552SCatalin Marinas 	/* map all the memory banks */
313c1cc1552SCatalin Marinas 	for_each_memblock(memory, reg) {
314c1cc1552SCatalin Marinas 		phys_addr_t start = reg->base;
315c1cc1552SCatalin Marinas 		phys_addr_t end = start + reg->size;
316c1cc1552SCatalin Marinas 
317c1cc1552SCatalin Marinas 		if (start >= end)
318c1cc1552SCatalin Marinas 			break;
319c1cc1552SCatalin Marinas 
320e25208f7SCatalin Marinas #ifndef CONFIG_ARM64_64K_PAGES
321e25208f7SCatalin Marinas 		/*
322e25208f7SCatalin Marinas 		 * For the first memory bank align the start address and
323e25208f7SCatalin Marinas 		 * current memblock limit to prevent create_mapping() from
324e25208f7SCatalin Marinas 		 * allocating pte page tables from unmapped memory.
325e25208f7SCatalin Marinas 		 * When 64K pages are enabled, the pte page table for the
326e25208f7SCatalin Marinas 		 * first PGDIR_SIZE is already present in swapper_pg_dir.
327e25208f7SCatalin Marinas 		 */
328e25208f7SCatalin Marinas 		if (start < limit)
329e25208f7SCatalin Marinas 			start = ALIGN(start, PMD_SIZE);
330e25208f7SCatalin Marinas 		if (end < limit) {
331e25208f7SCatalin Marinas 			limit = end & PMD_MASK;
332e25208f7SCatalin Marinas 			memblock_set_current_limit(limit);
333e25208f7SCatalin Marinas 		}
334e25208f7SCatalin Marinas #endif
335e25208f7SCatalin Marinas 
336c1cc1552SCatalin Marinas 		create_mapping(start, __phys_to_virt(start), end - start);
337c1cc1552SCatalin Marinas 	}
338f6bc87c3SSteve Capper 
339f6bc87c3SSteve Capper 	/* Limit no longer required. */
340f6bc87c3SSteve Capper 	memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE);
341c1cc1552SCatalin Marinas }
342c1cc1552SCatalin Marinas 
343c1cc1552SCatalin Marinas /*
344c1cc1552SCatalin Marinas  * paging_init() sets up the page tables, initialises the zone memory
345c1cc1552SCatalin Marinas  * maps and sets up the zero page.
346c1cc1552SCatalin Marinas  */
347c1cc1552SCatalin Marinas void __init paging_init(void)
348c1cc1552SCatalin Marinas {
349c1cc1552SCatalin Marinas 	void *zero_page;
350c1cc1552SCatalin Marinas 
351c1cc1552SCatalin Marinas 	map_mem();
352c1cc1552SCatalin Marinas 
353c1cc1552SCatalin Marinas 	/*
354c1cc1552SCatalin Marinas 	 * Finally flush the caches and tlb to ensure that we're in a
355c1cc1552SCatalin Marinas 	 * consistent state.
356c1cc1552SCatalin Marinas 	 */
357c1cc1552SCatalin Marinas 	flush_cache_all();
358c1cc1552SCatalin Marinas 	flush_tlb_all();
359c1cc1552SCatalin Marinas 
360c1cc1552SCatalin Marinas 	/* allocate the zero page. */
361c1cc1552SCatalin Marinas 	zero_page = early_alloc(PAGE_SIZE);
362c1cc1552SCatalin Marinas 
363c1cc1552SCatalin Marinas 	bootmem_init();
364c1cc1552SCatalin Marinas 
365c1cc1552SCatalin Marinas 	empty_zero_page = virt_to_page(zero_page);
366c1cc1552SCatalin Marinas 
367c1cc1552SCatalin Marinas 	/*
368c1cc1552SCatalin Marinas 	 * TTBR0 is only used for the identity mapping at this stage. Make it
369c1cc1552SCatalin Marinas 	 * point to zero page to avoid speculatively fetching new entries.
370c1cc1552SCatalin Marinas 	 */
371c1cc1552SCatalin Marinas 	cpu_set_reserved_ttbr0();
372c1cc1552SCatalin Marinas 	flush_tlb_all();
373c1cc1552SCatalin Marinas }
374c1cc1552SCatalin Marinas 
375c1cc1552SCatalin Marinas /*
376c1cc1552SCatalin Marinas  * Enable the identity mapping to allow the MMU disabling.
377c1cc1552SCatalin Marinas  */
378c1cc1552SCatalin Marinas void setup_mm_for_reboot(void)
379c1cc1552SCatalin Marinas {
380c1cc1552SCatalin Marinas 	cpu_switch_mm(idmap_pg_dir, &init_mm);
381c1cc1552SCatalin Marinas 	flush_tlb_all();
382c1cc1552SCatalin Marinas }
383c1cc1552SCatalin Marinas 
384c1cc1552SCatalin Marinas /*
385c1cc1552SCatalin Marinas  * Check whether a kernel address is valid (derived from arch/x86/).
386c1cc1552SCatalin Marinas  */
387c1cc1552SCatalin Marinas int kern_addr_valid(unsigned long addr)
388c1cc1552SCatalin Marinas {
389c1cc1552SCatalin Marinas 	pgd_t *pgd;
390c1cc1552SCatalin Marinas 	pud_t *pud;
391c1cc1552SCatalin Marinas 	pmd_t *pmd;
392c1cc1552SCatalin Marinas 	pte_t *pte;
393c1cc1552SCatalin Marinas 
394c1cc1552SCatalin Marinas 	if ((((long)addr) >> VA_BITS) != -1UL)
395c1cc1552SCatalin Marinas 		return 0;
396c1cc1552SCatalin Marinas 
397c1cc1552SCatalin Marinas 	pgd = pgd_offset_k(addr);
398c1cc1552SCatalin Marinas 	if (pgd_none(*pgd))
399c1cc1552SCatalin Marinas 		return 0;
400c1cc1552SCatalin Marinas 
401c1cc1552SCatalin Marinas 	pud = pud_offset(pgd, addr);
402c1cc1552SCatalin Marinas 	if (pud_none(*pud))
403c1cc1552SCatalin Marinas 		return 0;
404c1cc1552SCatalin Marinas 
405206a2a73SSteve Capper 	if (pud_sect(*pud))
406206a2a73SSteve Capper 		return pfn_valid(pud_pfn(*pud));
407206a2a73SSteve Capper 
408c1cc1552SCatalin Marinas 	pmd = pmd_offset(pud, addr);
409c1cc1552SCatalin Marinas 	if (pmd_none(*pmd))
410c1cc1552SCatalin Marinas 		return 0;
411c1cc1552SCatalin Marinas 
412da6e4cb6SDave Anderson 	if (pmd_sect(*pmd))
413da6e4cb6SDave Anderson 		return pfn_valid(pmd_pfn(*pmd));
414da6e4cb6SDave Anderson 
415c1cc1552SCatalin Marinas 	pte = pte_offset_kernel(pmd, addr);
416c1cc1552SCatalin Marinas 	if (pte_none(*pte))
417c1cc1552SCatalin Marinas 		return 0;
418c1cc1552SCatalin Marinas 
419c1cc1552SCatalin Marinas 	return pfn_valid(pte_pfn(*pte));
420c1cc1552SCatalin Marinas }
421c1cc1552SCatalin Marinas #ifdef CONFIG_SPARSEMEM_VMEMMAP
422c1cc1552SCatalin Marinas #ifdef CONFIG_ARM64_64K_PAGES
4230aad818bSJohannes Weiner int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
424c1cc1552SCatalin Marinas {
4250aad818bSJohannes Weiner 	return vmemmap_populate_basepages(start, end, node);
426c1cc1552SCatalin Marinas }
427c1cc1552SCatalin Marinas #else	/* !CONFIG_ARM64_64K_PAGES */
4280aad818bSJohannes Weiner int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
429c1cc1552SCatalin Marinas {
4300aad818bSJohannes Weiner 	unsigned long addr = start;
431c1cc1552SCatalin Marinas 	unsigned long next;
432c1cc1552SCatalin Marinas 	pgd_t *pgd;
433c1cc1552SCatalin Marinas 	pud_t *pud;
434c1cc1552SCatalin Marinas 	pmd_t *pmd;
435c1cc1552SCatalin Marinas 
436c1cc1552SCatalin Marinas 	do {
437c1cc1552SCatalin Marinas 		next = pmd_addr_end(addr, end);
438c1cc1552SCatalin Marinas 
439c1cc1552SCatalin Marinas 		pgd = vmemmap_pgd_populate(addr, node);
440c1cc1552SCatalin Marinas 		if (!pgd)
441c1cc1552SCatalin Marinas 			return -ENOMEM;
442c1cc1552SCatalin Marinas 
443c1cc1552SCatalin Marinas 		pud = vmemmap_pud_populate(pgd, addr, node);
444c1cc1552SCatalin Marinas 		if (!pud)
445c1cc1552SCatalin Marinas 			return -ENOMEM;
446c1cc1552SCatalin Marinas 
447c1cc1552SCatalin Marinas 		pmd = pmd_offset(pud, addr);
448c1cc1552SCatalin Marinas 		if (pmd_none(*pmd)) {
449c1cc1552SCatalin Marinas 			void *p = NULL;
450c1cc1552SCatalin Marinas 
451c1cc1552SCatalin Marinas 			p = vmemmap_alloc_block_buf(PMD_SIZE, node);
452c1cc1552SCatalin Marinas 			if (!p)
453c1cc1552SCatalin Marinas 				return -ENOMEM;
454c1cc1552SCatalin Marinas 
455a501e324SCatalin Marinas 			set_pmd(pmd, __pmd(__pa(p) | PROT_SECT_NORMAL));
456c1cc1552SCatalin Marinas 		} else
457c1cc1552SCatalin Marinas 			vmemmap_verify((pte_t *)pmd, node, addr, next);
458c1cc1552SCatalin Marinas 	} while (addr = next, addr != end);
459c1cc1552SCatalin Marinas 
460c1cc1552SCatalin Marinas 	return 0;
461c1cc1552SCatalin Marinas }
462c1cc1552SCatalin Marinas #endif	/* CONFIG_ARM64_64K_PAGES */
4630aad818bSJohannes Weiner void vmemmap_free(unsigned long start, unsigned long end)
4640197518cSTang Chen {
4650197518cSTang Chen }
466c1cc1552SCatalin Marinas #endif	/* CONFIG_SPARSEMEM_VMEMMAP */
467*af86e597SLaura Abbott 
468*af86e597SLaura Abbott static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
469*af86e597SLaura Abbott #if CONFIG_ARM64_PGTABLE_LEVELS > 2
470*af86e597SLaura Abbott static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss;
471*af86e597SLaura Abbott #endif
472*af86e597SLaura Abbott #if CONFIG_ARM64_PGTABLE_LEVELS > 3
473*af86e597SLaura Abbott static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss;
474*af86e597SLaura Abbott #endif
475*af86e597SLaura Abbott 
476*af86e597SLaura Abbott static inline pud_t * fixmap_pud(unsigned long addr)
477*af86e597SLaura Abbott {
478*af86e597SLaura Abbott 	pgd_t *pgd = pgd_offset_k(addr);
479*af86e597SLaura Abbott 
480*af86e597SLaura Abbott 	BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd));
481*af86e597SLaura Abbott 
482*af86e597SLaura Abbott 	return pud_offset(pgd, addr);
483*af86e597SLaura Abbott }
484*af86e597SLaura Abbott 
485*af86e597SLaura Abbott static inline pmd_t * fixmap_pmd(unsigned long addr)
486*af86e597SLaura Abbott {
487*af86e597SLaura Abbott 	pud_t *pud = fixmap_pud(addr);
488*af86e597SLaura Abbott 
489*af86e597SLaura Abbott 	BUG_ON(pud_none(*pud) || pud_bad(*pud));
490*af86e597SLaura Abbott 
491*af86e597SLaura Abbott 	return pmd_offset(pud, addr);
492*af86e597SLaura Abbott }
493*af86e597SLaura Abbott 
494*af86e597SLaura Abbott static inline pte_t * fixmap_pte(unsigned long addr)
495*af86e597SLaura Abbott {
496*af86e597SLaura Abbott 	pmd_t *pmd = fixmap_pmd(addr);
497*af86e597SLaura Abbott 
498*af86e597SLaura Abbott 	BUG_ON(pmd_none(*pmd) || pmd_bad(*pmd));
499*af86e597SLaura Abbott 
500*af86e597SLaura Abbott 	return pte_offset_kernel(pmd, addr);
501*af86e597SLaura Abbott }
502*af86e597SLaura Abbott 
503*af86e597SLaura Abbott void __init early_fixmap_init(void)
504*af86e597SLaura Abbott {
505*af86e597SLaura Abbott 	pgd_t *pgd;
506*af86e597SLaura Abbott 	pud_t *pud;
507*af86e597SLaura Abbott 	pmd_t *pmd;
508*af86e597SLaura Abbott 	unsigned long addr = FIXADDR_START;
509*af86e597SLaura Abbott 
510*af86e597SLaura Abbott 	pgd = pgd_offset_k(addr);
511*af86e597SLaura Abbott 	pgd_populate(&init_mm, pgd, bm_pud);
512*af86e597SLaura Abbott 	pud = pud_offset(pgd, addr);
513*af86e597SLaura Abbott 	pud_populate(&init_mm, pud, bm_pmd);
514*af86e597SLaura Abbott 	pmd = pmd_offset(pud, addr);
515*af86e597SLaura Abbott 	pmd_populate_kernel(&init_mm, pmd, bm_pte);
516*af86e597SLaura Abbott 
517*af86e597SLaura Abbott 	/*
518*af86e597SLaura Abbott 	 * The boot-ioremap range spans multiple pmds, for which
519*af86e597SLaura Abbott 	 * we are not preparted:
520*af86e597SLaura Abbott 	 */
521*af86e597SLaura Abbott 	BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT)
522*af86e597SLaura Abbott 		     != (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT));
523*af86e597SLaura Abbott 
524*af86e597SLaura Abbott 	if ((pmd != fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)))
525*af86e597SLaura Abbott 	     || pmd != fixmap_pmd(fix_to_virt(FIX_BTMAP_END))) {
526*af86e597SLaura Abbott 		WARN_ON(1);
527*af86e597SLaura Abbott 		pr_warn("pmd %p != %p, %p\n",
528*af86e597SLaura Abbott 			pmd, fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)),
529*af86e597SLaura Abbott 			fixmap_pmd(fix_to_virt(FIX_BTMAP_END)));
530*af86e597SLaura Abbott 		pr_warn("fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n",
531*af86e597SLaura Abbott 			fix_to_virt(FIX_BTMAP_BEGIN));
532*af86e597SLaura Abbott 		pr_warn("fix_to_virt(FIX_BTMAP_END):   %08lx\n",
533*af86e597SLaura Abbott 			fix_to_virt(FIX_BTMAP_END));
534*af86e597SLaura Abbott 
535*af86e597SLaura Abbott 		pr_warn("FIX_BTMAP_END:       %d\n", FIX_BTMAP_END);
536*af86e597SLaura Abbott 		pr_warn("FIX_BTMAP_BEGIN:     %d\n", FIX_BTMAP_BEGIN);
537*af86e597SLaura Abbott 	}
538*af86e597SLaura Abbott }
539*af86e597SLaura Abbott 
540*af86e597SLaura Abbott void __set_fixmap(enum fixed_addresses idx,
541*af86e597SLaura Abbott 			       phys_addr_t phys, pgprot_t flags)
542*af86e597SLaura Abbott {
543*af86e597SLaura Abbott 	unsigned long addr = __fix_to_virt(idx);
544*af86e597SLaura Abbott 	pte_t *pte;
545*af86e597SLaura Abbott 
546*af86e597SLaura Abbott 	if (idx >= __end_of_fixed_addresses) {
547*af86e597SLaura Abbott 		BUG();
548*af86e597SLaura Abbott 		return;
549*af86e597SLaura Abbott 	}
550*af86e597SLaura Abbott 
551*af86e597SLaura Abbott 	pte = fixmap_pte(addr);
552*af86e597SLaura Abbott 
553*af86e597SLaura Abbott 	if (pgprot_val(flags)) {
554*af86e597SLaura Abbott 		set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags));
555*af86e597SLaura Abbott 	} else {
556*af86e597SLaura Abbott 		pte_clear(&init_mm, addr, pte);
557*af86e597SLaura Abbott 		flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
558*af86e597SLaura Abbott 	}
559*af86e597SLaura Abbott }
560