162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  This file contains pgtable related functions for 64-bit machines.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Derived from arch/ppc64/mm/init.c
662306a36Sopenharmony_ci *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *  Modifications by Paul Mackerras (PowerMac) (paulus@samba.org)
962306a36Sopenharmony_ci *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
1062306a36Sopenharmony_ci *    Copyright (C) 1996 Paul Mackerras
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *  Derived from "arch/i386/mm/init.c"
1362306a36Sopenharmony_ci *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci *  Dave Engebretsen <engebret@us.ibm.com>
1662306a36Sopenharmony_ci *      Rework for PPC64 port.
1762306a36Sopenharmony_ci */
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <linux/signal.h>
2062306a36Sopenharmony_ci#include <linux/sched.h>
2162306a36Sopenharmony_ci#include <linux/kernel.h>
2262306a36Sopenharmony_ci#include <linux/errno.h>
2362306a36Sopenharmony_ci#include <linux/string.h>
2462306a36Sopenharmony_ci#include <linux/export.h>
2562306a36Sopenharmony_ci#include <linux/types.h>
2662306a36Sopenharmony_ci#include <linux/mman.h>
2762306a36Sopenharmony_ci#include <linux/mm.h>
2862306a36Sopenharmony_ci#include <linux/swap.h>
2962306a36Sopenharmony_ci#include <linux/stddef.h>
3062306a36Sopenharmony_ci#include <linux/vmalloc.h>
3162306a36Sopenharmony_ci#include <linux/slab.h>
3262306a36Sopenharmony_ci#include <linux/hugetlb.h>
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include <asm/page.h>
3562306a36Sopenharmony_ci#include <asm/mmu_context.h>
3662306a36Sopenharmony_ci#include <asm/mmu.h>
3762306a36Sopenharmony_ci#include <asm/smp.h>
3862306a36Sopenharmony_ci#include <asm/machdep.h>
3962306a36Sopenharmony_ci#include <asm/tlb.h>
4062306a36Sopenharmony_ci#include <asm/processor.h>
4162306a36Sopenharmony_ci#include <asm/cputable.h>
4262306a36Sopenharmony_ci#include <asm/sections.h>
4362306a36Sopenharmony_ci#include <asm/firmware.h>
4462306a36Sopenharmony_ci#include <asm/dma.h>
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#include <mm/mmu_decl.h>
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64
5062306a36Sopenharmony_ci/*
5162306a36Sopenharmony_ci * partition table and process table for ISA 3.0
5262306a36Sopenharmony_ci */
5362306a36Sopenharmony_cistruct prtb_entry *process_tb;
5462306a36Sopenharmony_cistruct patb_entry *partition_tb;
5562306a36Sopenharmony_ci/*
5662306a36Sopenharmony_ci * page table size
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_ciunsigned long __pte_index_size;
5962306a36Sopenharmony_ciEXPORT_SYMBOL(__pte_index_size);
6062306a36Sopenharmony_ciunsigned long __pmd_index_size;
6162306a36Sopenharmony_ciEXPORT_SYMBOL(__pmd_index_size);
6262306a36Sopenharmony_ciunsigned long __pud_index_size;
6362306a36Sopenharmony_ciEXPORT_SYMBOL(__pud_index_size);
6462306a36Sopenharmony_ciunsigned long __pgd_index_size;
6562306a36Sopenharmony_ciEXPORT_SYMBOL(__pgd_index_size);
6662306a36Sopenharmony_ciunsigned long __pud_cache_index;
6762306a36Sopenharmony_ciEXPORT_SYMBOL(__pud_cache_index);
6862306a36Sopenharmony_ciunsigned long __pte_table_size;
6962306a36Sopenharmony_ciEXPORT_SYMBOL(__pte_table_size);
7062306a36Sopenharmony_ciunsigned long __pmd_table_size;
7162306a36Sopenharmony_ciEXPORT_SYMBOL(__pmd_table_size);
7262306a36Sopenharmony_ciunsigned long __pud_table_size;
7362306a36Sopenharmony_ciEXPORT_SYMBOL(__pud_table_size);
7462306a36Sopenharmony_ciunsigned long __pgd_table_size;
7562306a36Sopenharmony_ciEXPORT_SYMBOL(__pgd_table_size);
7662306a36Sopenharmony_ciunsigned long __pmd_val_bits;
7762306a36Sopenharmony_ciEXPORT_SYMBOL(__pmd_val_bits);
7862306a36Sopenharmony_ciunsigned long __pud_val_bits;
7962306a36Sopenharmony_ciEXPORT_SYMBOL(__pud_val_bits);
8062306a36Sopenharmony_ciunsigned long __pgd_val_bits;
8162306a36Sopenharmony_ciEXPORT_SYMBOL(__pgd_val_bits);
8262306a36Sopenharmony_ciunsigned long __kernel_virt_start;
8362306a36Sopenharmony_ciEXPORT_SYMBOL(__kernel_virt_start);
8462306a36Sopenharmony_ciunsigned long __vmalloc_start;
8562306a36Sopenharmony_ciEXPORT_SYMBOL(__vmalloc_start);
8662306a36Sopenharmony_ciunsigned long __vmalloc_end;
8762306a36Sopenharmony_ciEXPORT_SYMBOL(__vmalloc_end);
8862306a36Sopenharmony_ciunsigned long __kernel_io_start;
8962306a36Sopenharmony_ciEXPORT_SYMBOL(__kernel_io_start);
9062306a36Sopenharmony_ciunsigned long __kernel_io_end;
9162306a36Sopenharmony_cistruct page *vmemmap;
9262306a36Sopenharmony_ciEXPORT_SYMBOL(vmemmap);
9362306a36Sopenharmony_ciunsigned long __pte_frag_nr;
9462306a36Sopenharmony_ciEXPORT_SYMBOL(__pte_frag_nr);
9562306a36Sopenharmony_ciunsigned long __pte_frag_size_shift;
9662306a36Sopenharmony_ciEXPORT_SYMBOL(__pte_frag_size_shift);
9762306a36Sopenharmony_ci#endif
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#ifndef __PAGETABLE_PUD_FOLDED
10062306a36Sopenharmony_ci/* 4 level page table */
10162306a36Sopenharmony_cistruct page *p4d_page(p4d_t p4d)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	if (p4d_is_leaf(p4d)) {
10462306a36Sopenharmony_ci		if (!IS_ENABLED(CONFIG_HAVE_ARCH_HUGE_VMAP))
10562306a36Sopenharmony_ci			VM_WARN_ON(!p4d_huge(p4d));
10662306a36Sopenharmony_ci		return pte_page(p4d_pte(p4d));
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci	return virt_to_page(p4d_pgtable(p4d));
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci#endif
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistruct page *pud_page(pud_t pud)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	if (pud_is_leaf(pud)) {
11562306a36Sopenharmony_ci		if (!IS_ENABLED(CONFIG_HAVE_ARCH_HUGE_VMAP))
11662306a36Sopenharmony_ci			VM_WARN_ON(!pud_huge(pud));
11762306a36Sopenharmony_ci		return pte_page(pud_pte(pud));
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci	return virt_to_page(pud_pgtable(pud));
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/*
12362306a36Sopenharmony_ci * For hugepage we have pfn in the pmd, we use PTE_RPN_SHIFT bits for flags
12462306a36Sopenharmony_ci * For PTE page, we have a PTE_FRAG_SIZE (4K) aligned virtual address.
12562306a36Sopenharmony_ci */
12662306a36Sopenharmony_cistruct page *pmd_page(pmd_t pmd)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	if (pmd_is_leaf(pmd)) {
12962306a36Sopenharmony_ci		/*
13062306a36Sopenharmony_ci		 * vmalloc_to_page may be called on any vmap address (not only
13162306a36Sopenharmony_ci		 * vmalloc), and it uses pmd_page() etc., when huge vmap is
13262306a36Sopenharmony_ci		 * enabled so these checks can't be used.
13362306a36Sopenharmony_ci		 */
13462306a36Sopenharmony_ci		if (!IS_ENABLED(CONFIG_HAVE_ARCH_HUGE_VMAP))
13562306a36Sopenharmony_ci			VM_WARN_ON(!(pmd_large(pmd) || pmd_huge(pmd)));
13662306a36Sopenharmony_ci		return pte_page(pmd_pte(pmd));
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci	return virt_to_page(pmd_page_vaddr(pmd));
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci#ifdef CONFIG_STRICT_KERNEL_RWX
14262306a36Sopenharmony_civoid mark_rodata_ro(void)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	if (!mmu_has_feature(MMU_FTR_KERNEL_RO)) {
14562306a36Sopenharmony_ci		pr_warn("Warning: Unable to mark rodata read only on this CPU.\n");
14662306a36Sopenharmony_ci		return;
14762306a36Sopenharmony_ci	}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	if (radix_enabled())
15062306a36Sopenharmony_ci		radix__mark_rodata_ro();
15162306a36Sopenharmony_ci	else
15262306a36Sopenharmony_ci		hash__mark_rodata_ro();
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	// mark_initmem_nx() should have already run by now
15562306a36Sopenharmony_ci	ptdump_check_wx();
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_civoid mark_initmem_nx(void)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	if (radix_enabled())
16162306a36Sopenharmony_ci		radix__mark_initmem_nx();
16262306a36Sopenharmony_ci	else
16362306a36Sopenharmony_ci		hash__mark_initmem_nx();
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci#endif
166