18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Initialize MMU support.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 1998-2003 Hewlett-Packard Co
68c2ecf20Sopenharmony_ci *	David Mosberger-Tang <davidm@hpl.hp.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/kernel.h>
98c2ecf20Sopenharmony_ci#include <linux/init.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/dma-map-ops.h>
128c2ecf20Sopenharmony_ci#include <linux/dmar.h>
138c2ecf20Sopenharmony_ci#include <linux/efi.h>
148c2ecf20Sopenharmony_ci#include <linux/elf.h>
158c2ecf20Sopenharmony_ci#include <linux/memblock.h>
168c2ecf20Sopenharmony_ci#include <linux/mm.h>
178c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
188c2ecf20Sopenharmony_ci#include <linux/mmzone.h>
198c2ecf20Sopenharmony_ci#include <linux/module.h>
208c2ecf20Sopenharmony_ci#include <linux/personality.h>
218c2ecf20Sopenharmony_ci#include <linux/reboot.h>
228c2ecf20Sopenharmony_ci#include <linux/slab.h>
238c2ecf20Sopenharmony_ci#include <linux/swap.h>
248c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
258c2ecf20Sopenharmony_ci#include <linux/bitops.h>
268c2ecf20Sopenharmony_ci#include <linux/kexec.h>
278c2ecf20Sopenharmony_ci#include <linux/swiotlb.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include <asm/dma.h>
308c2ecf20Sopenharmony_ci#include <asm/io.h>
318c2ecf20Sopenharmony_ci#include <asm/numa.h>
328c2ecf20Sopenharmony_ci#include <asm/patch.h>
338c2ecf20Sopenharmony_ci#include <asm/pgalloc.h>
348c2ecf20Sopenharmony_ci#include <asm/sal.h>
358c2ecf20Sopenharmony_ci#include <asm/sections.h>
368c2ecf20Sopenharmony_ci#include <asm/tlb.h>
378c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
388c2ecf20Sopenharmony_ci#include <asm/unistd.h>
398c2ecf20Sopenharmony_ci#include <asm/mca.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ciextern void ia64_tlb_init (void);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ciunsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#ifdef CONFIG_VIRTUAL_MEM_MAP
468c2ecf20Sopenharmony_ciunsigned long VMALLOC_END = VMALLOC_END_INIT;
478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(VMALLOC_END);
488c2ecf20Sopenharmony_cistruct page *vmem_map;
498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vmem_map);
508c2ecf20Sopenharmony_ci#endif
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistruct page *zero_page_memmap_ptr;	/* map entry for zero page */
538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(zero_page_memmap_ptr);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_civoid
568c2ecf20Sopenharmony_ci__ia64_sync_icache_dcache (pte_t pte)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	unsigned long addr;
598c2ecf20Sopenharmony_ci	struct page *page;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	page = pte_page(pte);
628c2ecf20Sopenharmony_ci	addr = (unsigned long) page_address(page);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	if (test_bit(PG_arch_1, &page->flags))
658c2ecf20Sopenharmony_ci		return;				/* i-cache is already coherent with d-cache */
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	flush_icache_range(addr, addr + page_size(page));
688c2ecf20Sopenharmony_ci	set_bit(PG_arch_1, &page->flags);	/* mark page as clean */
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci/*
728c2ecf20Sopenharmony_ci * Since DMA is i-cache coherent, any (complete) pages that were written via
738c2ecf20Sopenharmony_ci * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to
748c2ecf20Sopenharmony_ci * flush them when they get mapped into an executable vm-area.
758c2ecf20Sopenharmony_ci */
768c2ecf20Sopenharmony_civoid arch_dma_mark_clean(phys_addr_t paddr, size_t size)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	unsigned long pfn = PHYS_PFN(paddr);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	do {
818c2ecf20Sopenharmony_ci		set_bit(PG_arch_1, &pfn_to_page(pfn)->flags);
828c2ecf20Sopenharmony_ci	} while (++pfn <= PHYS_PFN(paddr + size - 1));
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ciinline void
868c2ecf20Sopenharmony_ciia64_set_rbs_bot (void)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	unsigned long stack_size = rlimit_max(RLIMIT_STACK) & -16;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	if (stack_size > MAX_USER_STACK_SIZE)
918c2ecf20Sopenharmony_ci		stack_size = MAX_USER_STACK_SIZE;
928c2ecf20Sopenharmony_ci	current->thread.rbs_bot = PAGE_ALIGN(current->mm->start_stack - stack_size);
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci/*
968c2ecf20Sopenharmony_ci * This performs some platform-dependent address space initialization.
978c2ecf20Sopenharmony_ci * On IA-64, we want to setup the VM area for the register backing
988c2ecf20Sopenharmony_ci * store (which grows upwards) and install the gateway page which is
998c2ecf20Sopenharmony_ci * used for signal trampolines, etc.
1008c2ecf20Sopenharmony_ci */
1018c2ecf20Sopenharmony_civoid
1028c2ecf20Sopenharmony_ciia64_init_addr_space (void)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	struct vm_area_struct *vma;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	ia64_set_rbs_bot();
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	/*
1098c2ecf20Sopenharmony_ci	 * If we're out of memory and kmem_cache_alloc() returns NULL, we simply ignore
1108c2ecf20Sopenharmony_ci	 * the problem.  When the process attempts to write to the register backing store
1118c2ecf20Sopenharmony_ci	 * for the first time, it will get a SEGFAULT in this case.
1128c2ecf20Sopenharmony_ci	 */
1138c2ecf20Sopenharmony_ci	vma = vm_area_alloc(current->mm);
1148c2ecf20Sopenharmony_ci	if (vma) {
1158c2ecf20Sopenharmony_ci		vma_set_anonymous(vma);
1168c2ecf20Sopenharmony_ci		vma->vm_start = current->thread.rbs_bot & PAGE_MASK;
1178c2ecf20Sopenharmony_ci		vma->vm_end = vma->vm_start + PAGE_SIZE;
1188c2ecf20Sopenharmony_ci		vma->vm_flags = VM_DATA_DEFAULT_FLAGS|VM_GROWSUP|VM_ACCOUNT;
1198c2ecf20Sopenharmony_ci		vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
1208c2ecf20Sopenharmony_ci		mmap_write_lock(current->mm);
1218c2ecf20Sopenharmony_ci		if (insert_vm_struct(current->mm, vma)) {
1228c2ecf20Sopenharmony_ci			mmap_write_unlock(current->mm);
1238c2ecf20Sopenharmony_ci			vm_area_free(vma);
1248c2ecf20Sopenharmony_ci			return;
1258c2ecf20Sopenharmony_ci		}
1268c2ecf20Sopenharmony_ci		mmap_write_unlock(current->mm);
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	/* map NaT-page at address zero to speed up speculative dereferencing of NULL: */
1308c2ecf20Sopenharmony_ci	if (!(current->personality & MMAP_PAGE_ZERO)) {
1318c2ecf20Sopenharmony_ci		vma = vm_area_alloc(current->mm);
1328c2ecf20Sopenharmony_ci		if (vma) {
1338c2ecf20Sopenharmony_ci			vma_set_anonymous(vma);
1348c2ecf20Sopenharmony_ci			vma->vm_end = PAGE_SIZE;
1358c2ecf20Sopenharmony_ci			vma->vm_page_prot = __pgprot(pgprot_val(PAGE_READONLY) | _PAGE_MA_NAT);
1368c2ecf20Sopenharmony_ci			vma->vm_flags = VM_READ | VM_MAYREAD | VM_IO |
1378c2ecf20Sopenharmony_ci					VM_DONTEXPAND | VM_DONTDUMP;
1388c2ecf20Sopenharmony_ci			mmap_write_lock(current->mm);
1398c2ecf20Sopenharmony_ci			if (insert_vm_struct(current->mm, vma)) {
1408c2ecf20Sopenharmony_ci				mmap_write_unlock(current->mm);
1418c2ecf20Sopenharmony_ci				vm_area_free(vma);
1428c2ecf20Sopenharmony_ci				return;
1438c2ecf20Sopenharmony_ci			}
1448c2ecf20Sopenharmony_ci			mmap_write_unlock(current->mm);
1458c2ecf20Sopenharmony_ci		}
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_civoid
1508c2ecf20Sopenharmony_cifree_initmem (void)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	free_reserved_area(ia64_imva(__init_begin), ia64_imva(__init_end),
1538c2ecf20Sopenharmony_ci			   -1, "unused kernel");
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_civoid __init
1578c2ecf20Sopenharmony_cifree_initrd_mem (unsigned long start, unsigned long end)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	/*
1608c2ecf20Sopenharmony_ci	 * EFI uses 4KB pages while the kernel can use 4KB or bigger.
1618c2ecf20Sopenharmony_ci	 * Thus EFI and the kernel may have different page sizes. It is
1628c2ecf20Sopenharmony_ci	 * therefore possible to have the initrd share the same page as
1638c2ecf20Sopenharmony_ci	 * the end of the kernel (given current setup).
1648c2ecf20Sopenharmony_ci	 *
1658c2ecf20Sopenharmony_ci	 * To avoid freeing/using the wrong page (kernel sized) we:
1668c2ecf20Sopenharmony_ci	 *	- align up the beginning of initrd
1678c2ecf20Sopenharmony_ci	 *	- align down the end of initrd
1688c2ecf20Sopenharmony_ci	 *
1698c2ecf20Sopenharmony_ci	 *  |             |
1708c2ecf20Sopenharmony_ci	 *  |=============| a000
1718c2ecf20Sopenharmony_ci	 *  |             |
1728c2ecf20Sopenharmony_ci	 *  |             |
1738c2ecf20Sopenharmony_ci	 *  |             | 9000
1748c2ecf20Sopenharmony_ci	 *  |/////////////|
1758c2ecf20Sopenharmony_ci	 *  |/////////////|
1768c2ecf20Sopenharmony_ci	 *  |=============| 8000
1778c2ecf20Sopenharmony_ci	 *  |///INITRD////|
1788c2ecf20Sopenharmony_ci	 *  |/////////////|
1798c2ecf20Sopenharmony_ci	 *  |/////////////| 7000
1808c2ecf20Sopenharmony_ci	 *  |             |
1818c2ecf20Sopenharmony_ci	 *  |KKKKKKKKKKKKK|
1828c2ecf20Sopenharmony_ci	 *  |=============| 6000
1838c2ecf20Sopenharmony_ci	 *  |KKKKKKKKKKKKK|
1848c2ecf20Sopenharmony_ci	 *  |KKKKKKKKKKKKK|
1858c2ecf20Sopenharmony_ci	 *  K=kernel using 8KB pages
1868c2ecf20Sopenharmony_ci	 *
1878c2ecf20Sopenharmony_ci	 * In this example, we must free page 8000 ONLY. So we must align up
1888c2ecf20Sopenharmony_ci	 * initrd_start and keep initrd_end as is.
1898c2ecf20Sopenharmony_ci	 */
1908c2ecf20Sopenharmony_ci	start = PAGE_ALIGN(start);
1918c2ecf20Sopenharmony_ci	end = end & PAGE_MASK;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	if (start < end)
1948c2ecf20Sopenharmony_ci		printk(KERN_INFO "Freeing initrd memory: %ldkB freed\n", (end - start) >> 10);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	for (; start < end; start += PAGE_SIZE) {
1978c2ecf20Sopenharmony_ci		if (!virt_addr_valid(start))
1988c2ecf20Sopenharmony_ci			continue;
1998c2ecf20Sopenharmony_ci		free_reserved_page(virt_to_page(start));
2008c2ecf20Sopenharmony_ci	}
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci/*
2048c2ecf20Sopenharmony_ci * This installs a clean page in the kernel's page table.
2058c2ecf20Sopenharmony_ci */
2068c2ecf20Sopenharmony_cistatic struct page * __init
2078c2ecf20Sopenharmony_ciput_kernel_page (struct page *page, unsigned long address, pgprot_t pgprot)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	pgd_t *pgd;
2108c2ecf20Sopenharmony_ci	p4d_t *p4d;
2118c2ecf20Sopenharmony_ci	pud_t *pud;
2128c2ecf20Sopenharmony_ci	pmd_t *pmd;
2138c2ecf20Sopenharmony_ci	pte_t *pte;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	pgd = pgd_offset_k(address);		/* note: this is NOT pgd_offset()! */
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	{
2188c2ecf20Sopenharmony_ci		p4d = p4d_alloc(&init_mm, pgd, address);
2198c2ecf20Sopenharmony_ci		if (!p4d)
2208c2ecf20Sopenharmony_ci			goto out;
2218c2ecf20Sopenharmony_ci		pud = pud_alloc(&init_mm, p4d, address);
2228c2ecf20Sopenharmony_ci		if (!pud)
2238c2ecf20Sopenharmony_ci			goto out;
2248c2ecf20Sopenharmony_ci		pmd = pmd_alloc(&init_mm, pud, address);
2258c2ecf20Sopenharmony_ci		if (!pmd)
2268c2ecf20Sopenharmony_ci			goto out;
2278c2ecf20Sopenharmony_ci		pte = pte_alloc_kernel(pmd, address);
2288c2ecf20Sopenharmony_ci		if (!pte)
2298c2ecf20Sopenharmony_ci			goto out;
2308c2ecf20Sopenharmony_ci		if (!pte_none(*pte))
2318c2ecf20Sopenharmony_ci			goto out;
2328c2ecf20Sopenharmony_ci		set_pte(pte, mk_pte(page, pgprot));
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci  out:
2358c2ecf20Sopenharmony_ci	/* no need for flush_tlb */
2368c2ecf20Sopenharmony_ci	return page;
2378c2ecf20Sopenharmony_ci}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cistatic void __init
2408c2ecf20Sopenharmony_cisetup_gate (void)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	struct page *page;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	/*
2458c2ecf20Sopenharmony_ci	 * Map the gate page twice: once read-only to export the ELF
2468c2ecf20Sopenharmony_ci	 * headers etc. and once execute-only page to enable
2478c2ecf20Sopenharmony_ci	 * privilege-promotion via "epc":
2488c2ecf20Sopenharmony_ci	 */
2498c2ecf20Sopenharmony_ci	page = virt_to_page(ia64_imva(__start_gate_section));
2508c2ecf20Sopenharmony_ci	put_kernel_page(page, GATE_ADDR, PAGE_READONLY);
2518c2ecf20Sopenharmony_ci#ifdef HAVE_BUGGY_SEGREL
2528c2ecf20Sopenharmony_ci	page = virt_to_page(ia64_imva(__start_gate_section + PAGE_SIZE));
2538c2ecf20Sopenharmony_ci	put_kernel_page(page, GATE_ADDR + PAGE_SIZE, PAGE_GATE);
2548c2ecf20Sopenharmony_ci#else
2558c2ecf20Sopenharmony_ci	put_kernel_page(page, GATE_ADDR + PERCPU_PAGE_SIZE, PAGE_GATE);
2568c2ecf20Sopenharmony_ci	/* Fill in the holes (if any) with read-only zero pages: */
2578c2ecf20Sopenharmony_ci	{
2588c2ecf20Sopenharmony_ci		unsigned long addr;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci		for (addr = GATE_ADDR + PAGE_SIZE;
2618c2ecf20Sopenharmony_ci		     addr < GATE_ADDR + PERCPU_PAGE_SIZE;
2628c2ecf20Sopenharmony_ci		     addr += PAGE_SIZE)
2638c2ecf20Sopenharmony_ci		{
2648c2ecf20Sopenharmony_ci			put_kernel_page(ZERO_PAGE(0), addr,
2658c2ecf20Sopenharmony_ci					PAGE_READONLY);
2668c2ecf20Sopenharmony_ci			put_kernel_page(ZERO_PAGE(0), addr + PERCPU_PAGE_SIZE,
2678c2ecf20Sopenharmony_ci					PAGE_READONLY);
2688c2ecf20Sopenharmony_ci		}
2698c2ecf20Sopenharmony_ci	}
2708c2ecf20Sopenharmony_ci#endif
2718c2ecf20Sopenharmony_ci	ia64_patch_gate();
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic struct vm_area_struct gate_vma;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic int __init gate_vma_init(void)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	vma_init(&gate_vma, NULL);
2798c2ecf20Sopenharmony_ci	gate_vma.vm_start = FIXADDR_USER_START;
2808c2ecf20Sopenharmony_ci	gate_vma.vm_end = FIXADDR_USER_END;
2818c2ecf20Sopenharmony_ci	gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC;
2828c2ecf20Sopenharmony_ci	gate_vma.vm_page_prot = __P101;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	return 0;
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci__initcall(gate_vma_init);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_cistruct vm_area_struct *get_gate_vma(struct mm_struct *mm)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	return &gate_vma;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ciint in_gate_area_no_mm(unsigned long addr)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	if ((addr >= FIXADDR_USER_START) && (addr < FIXADDR_USER_END))
2968c2ecf20Sopenharmony_ci		return 1;
2978c2ecf20Sopenharmony_ci	return 0;
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ciint in_gate_area(struct mm_struct *mm, unsigned long addr)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	return in_gate_area_no_mm(addr);
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_civoid ia64_mmu_init(void *my_cpu_data)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	unsigned long pta, impl_va_bits;
3088c2ecf20Sopenharmony_ci	extern void tlb_init(void);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci#ifdef CONFIG_DISABLE_VHPT
3118c2ecf20Sopenharmony_ci#	define VHPT_ENABLE_BIT	0
3128c2ecf20Sopenharmony_ci#else
3138c2ecf20Sopenharmony_ci#	define VHPT_ENABLE_BIT	1
3148c2ecf20Sopenharmony_ci#endif
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	/*
3178c2ecf20Sopenharmony_ci	 * Check if the virtually mapped linear page table (VMLPT) overlaps with a mapped
3188c2ecf20Sopenharmony_ci	 * address space.  The IA-64 architecture guarantees that at least 50 bits of
3198c2ecf20Sopenharmony_ci	 * virtual address space are implemented but if we pick a large enough page size
3208c2ecf20Sopenharmony_ci	 * (e.g., 64KB), the mapped address space is big enough that it will overlap with
3218c2ecf20Sopenharmony_ci	 * VMLPT.  I assume that once we run on machines big enough to warrant 64KB pages,
3228c2ecf20Sopenharmony_ci	 * IMPL_VA_MSB will be significantly bigger, so this is unlikely to become a
3238c2ecf20Sopenharmony_ci	 * problem in practice.  Alternatively, we could truncate the top of the mapped
3248c2ecf20Sopenharmony_ci	 * address space to not permit mappings that would overlap with the VMLPT.
3258c2ecf20Sopenharmony_ci	 * --davidm 00/12/06
3268c2ecf20Sopenharmony_ci	 */
3278c2ecf20Sopenharmony_ci#	define pte_bits			3
3288c2ecf20Sopenharmony_ci#	define mapped_space_bits	(3*(PAGE_SHIFT - pte_bits) + PAGE_SHIFT)
3298c2ecf20Sopenharmony_ci	/*
3308c2ecf20Sopenharmony_ci	 * The virtual page table has to cover the entire implemented address space within
3318c2ecf20Sopenharmony_ci	 * a region even though not all of this space may be mappable.  The reason for
3328c2ecf20Sopenharmony_ci	 * this is that the Access bit and Dirty bit fault handlers perform
3338c2ecf20Sopenharmony_ci	 * non-speculative accesses to the virtual page table, so the address range of the
3348c2ecf20Sopenharmony_ci	 * virtual page table itself needs to be covered by virtual page table.
3358c2ecf20Sopenharmony_ci	 */
3368c2ecf20Sopenharmony_ci#	define vmlpt_bits		(impl_va_bits - PAGE_SHIFT + pte_bits)
3378c2ecf20Sopenharmony_ci#	define POW2(n)			(1ULL << (n))
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	impl_va_bits = ffz(~(local_cpu_data->unimpl_va_mask | (7UL << 61)));
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	if (impl_va_bits < 51 || impl_va_bits > 61)
3428c2ecf20Sopenharmony_ci		panic("CPU has bogus IMPL_VA_MSB value of %lu!\n", impl_va_bits - 1);
3438c2ecf20Sopenharmony_ci	/*
3448c2ecf20Sopenharmony_ci	 * mapped_space_bits - PAGE_SHIFT is the total number of ptes we need,
3458c2ecf20Sopenharmony_ci	 * which must fit into "vmlpt_bits - pte_bits" slots. Second half of
3468c2ecf20Sopenharmony_ci	 * the test makes sure that our mapped space doesn't overlap the
3478c2ecf20Sopenharmony_ci	 * unimplemented hole in the middle of the region.
3488c2ecf20Sopenharmony_ci	 */
3498c2ecf20Sopenharmony_ci	if ((mapped_space_bits - PAGE_SHIFT > vmlpt_bits - pte_bits) ||
3508c2ecf20Sopenharmony_ci	    (mapped_space_bits > impl_va_bits - 1))
3518c2ecf20Sopenharmony_ci		panic("Cannot build a big enough virtual-linear page table"
3528c2ecf20Sopenharmony_ci		      " to cover mapped address space.\n"
3538c2ecf20Sopenharmony_ci		      " Try using a smaller page size.\n");
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	/* place the VMLPT at the end of each page-table mapped region: */
3578c2ecf20Sopenharmony_ci	pta = POW2(61) - POW2(vmlpt_bits);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	/*
3608c2ecf20Sopenharmony_ci	 * Set the (virtually mapped linear) page table address.  Bit
3618c2ecf20Sopenharmony_ci	 * 8 selects between the short and long format, bits 2-7 the
3628c2ecf20Sopenharmony_ci	 * size of the table, and bit 0 whether the VHPT walker is
3638c2ecf20Sopenharmony_ci	 * enabled.
3648c2ecf20Sopenharmony_ci	 */
3658c2ecf20Sopenharmony_ci	ia64_set_pta(pta | (0 << 8) | (vmlpt_bits << 2) | VHPT_ENABLE_BIT);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	ia64_tlb_init();
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci#ifdef	CONFIG_HUGETLB_PAGE
3708c2ecf20Sopenharmony_ci	ia64_set_rr(HPAGE_REGION_BASE, HPAGE_SHIFT << 2);
3718c2ecf20Sopenharmony_ci	ia64_srlz_d();
3728c2ecf20Sopenharmony_ci#endif
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci#ifdef CONFIG_VIRTUAL_MEM_MAP
3768c2ecf20Sopenharmony_ciint vmemmap_find_next_valid_pfn(int node, int i)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	unsigned long end_address, hole_next_pfn;
3798c2ecf20Sopenharmony_ci	unsigned long stop_address;
3808c2ecf20Sopenharmony_ci	pg_data_t *pgdat = NODE_DATA(node);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	end_address = (unsigned long) &vmem_map[pgdat->node_start_pfn + i];
3838c2ecf20Sopenharmony_ci	end_address = PAGE_ALIGN(end_address);
3848c2ecf20Sopenharmony_ci	stop_address = (unsigned long) &vmem_map[pgdat_end_pfn(pgdat)];
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	do {
3878c2ecf20Sopenharmony_ci		pgd_t *pgd;
3888c2ecf20Sopenharmony_ci		p4d_t *p4d;
3898c2ecf20Sopenharmony_ci		pud_t *pud;
3908c2ecf20Sopenharmony_ci		pmd_t *pmd;
3918c2ecf20Sopenharmony_ci		pte_t *pte;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci		pgd = pgd_offset_k(end_address);
3948c2ecf20Sopenharmony_ci		if (pgd_none(*pgd)) {
3958c2ecf20Sopenharmony_ci			end_address += PGDIR_SIZE;
3968c2ecf20Sopenharmony_ci			continue;
3978c2ecf20Sopenharmony_ci		}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci		p4d = p4d_offset(pgd, end_address);
4008c2ecf20Sopenharmony_ci		if (p4d_none(*p4d)) {
4018c2ecf20Sopenharmony_ci			end_address += P4D_SIZE;
4028c2ecf20Sopenharmony_ci			continue;
4038c2ecf20Sopenharmony_ci		}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci		pud = pud_offset(p4d, end_address);
4068c2ecf20Sopenharmony_ci		if (pud_none(*pud)) {
4078c2ecf20Sopenharmony_ci			end_address += PUD_SIZE;
4088c2ecf20Sopenharmony_ci			continue;
4098c2ecf20Sopenharmony_ci		}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci		pmd = pmd_offset(pud, end_address);
4128c2ecf20Sopenharmony_ci		if (pmd_none(*pmd)) {
4138c2ecf20Sopenharmony_ci			end_address += PMD_SIZE;
4148c2ecf20Sopenharmony_ci			continue;
4158c2ecf20Sopenharmony_ci		}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci		pte = pte_offset_kernel(pmd, end_address);
4188c2ecf20Sopenharmony_ciretry_pte:
4198c2ecf20Sopenharmony_ci		if (pte_none(*pte)) {
4208c2ecf20Sopenharmony_ci			end_address += PAGE_SIZE;
4218c2ecf20Sopenharmony_ci			pte++;
4228c2ecf20Sopenharmony_ci			if ((end_address < stop_address) &&
4238c2ecf20Sopenharmony_ci			    (end_address != ALIGN(end_address, 1UL << PMD_SHIFT)))
4248c2ecf20Sopenharmony_ci				goto retry_pte;
4258c2ecf20Sopenharmony_ci			continue;
4268c2ecf20Sopenharmony_ci		}
4278c2ecf20Sopenharmony_ci		/* Found next valid vmem_map page */
4288c2ecf20Sopenharmony_ci		break;
4298c2ecf20Sopenharmony_ci	} while (end_address < stop_address);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	end_address = min(end_address, stop_address);
4328c2ecf20Sopenharmony_ci	end_address = end_address - (unsigned long) vmem_map + sizeof(struct page) - 1;
4338c2ecf20Sopenharmony_ci	hole_next_pfn = end_address / sizeof(struct page);
4348c2ecf20Sopenharmony_ci	return hole_next_pfn - pgdat->node_start_pfn;
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ciint __init create_mem_map_page_table(u64 start, u64 end, void *arg)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	unsigned long address, start_page, end_page;
4408c2ecf20Sopenharmony_ci	struct page *map_start, *map_end;
4418c2ecf20Sopenharmony_ci	int node;
4428c2ecf20Sopenharmony_ci	pgd_t *pgd;
4438c2ecf20Sopenharmony_ci	p4d_t *p4d;
4448c2ecf20Sopenharmony_ci	pud_t *pud;
4458c2ecf20Sopenharmony_ci	pmd_t *pmd;
4468c2ecf20Sopenharmony_ci	pte_t *pte;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	map_start = vmem_map + (__pa(start) >> PAGE_SHIFT);
4498c2ecf20Sopenharmony_ci	map_end   = vmem_map + (__pa(end) >> PAGE_SHIFT);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	start_page = (unsigned long) map_start & PAGE_MASK;
4528c2ecf20Sopenharmony_ci	end_page = PAGE_ALIGN((unsigned long) map_end);
4538c2ecf20Sopenharmony_ci	node = paddr_to_nid(__pa(start));
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	for (address = start_page; address < end_page; address += PAGE_SIZE) {
4568c2ecf20Sopenharmony_ci		pgd = pgd_offset_k(address);
4578c2ecf20Sopenharmony_ci		if (pgd_none(*pgd)) {
4588c2ecf20Sopenharmony_ci			p4d = memblock_alloc_node(PAGE_SIZE, PAGE_SIZE, node);
4598c2ecf20Sopenharmony_ci			if (!p4d)
4608c2ecf20Sopenharmony_ci				goto err_alloc;
4618c2ecf20Sopenharmony_ci			pgd_populate(&init_mm, pgd, p4d);
4628c2ecf20Sopenharmony_ci		}
4638c2ecf20Sopenharmony_ci		p4d = p4d_offset(pgd, address);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci		if (p4d_none(*p4d)) {
4668c2ecf20Sopenharmony_ci			pud = memblock_alloc_node(PAGE_SIZE, PAGE_SIZE, node);
4678c2ecf20Sopenharmony_ci			if (!pud)
4688c2ecf20Sopenharmony_ci				goto err_alloc;
4698c2ecf20Sopenharmony_ci			p4d_populate(&init_mm, p4d, pud);
4708c2ecf20Sopenharmony_ci		}
4718c2ecf20Sopenharmony_ci		pud = pud_offset(p4d, address);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci		if (pud_none(*pud)) {
4748c2ecf20Sopenharmony_ci			pmd = memblock_alloc_node(PAGE_SIZE, PAGE_SIZE, node);
4758c2ecf20Sopenharmony_ci			if (!pmd)
4768c2ecf20Sopenharmony_ci				goto err_alloc;
4778c2ecf20Sopenharmony_ci			pud_populate(&init_mm, pud, pmd);
4788c2ecf20Sopenharmony_ci		}
4798c2ecf20Sopenharmony_ci		pmd = pmd_offset(pud, address);
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci		if (pmd_none(*pmd)) {
4828c2ecf20Sopenharmony_ci			pte = memblock_alloc_node(PAGE_SIZE, PAGE_SIZE, node);
4838c2ecf20Sopenharmony_ci			if (!pte)
4848c2ecf20Sopenharmony_ci				goto err_alloc;
4858c2ecf20Sopenharmony_ci			pmd_populate_kernel(&init_mm, pmd, pte);
4868c2ecf20Sopenharmony_ci		}
4878c2ecf20Sopenharmony_ci		pte = pte_offset_kernel(pmd, address);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci		if (pte_none(*pte)) {
4908c2ecf20Sopenharmony_ci			void *page = memblock_alloc_node(PAGE_SIZE, PAGE_SIZE,
4918c2ecf20Sopenharmony_ci							 node);
4928c2ecf20Sopenharmony_ci			if (!page)
4938c2ecf20Sopenharmony_ci				goto err_alloc;
4948c2ecf20Sopenharmony_ci			set_pte(pte, pfn_pte(__pa(page) >> PAGE_SHIFT,
4958c2ecf20Sopenharmony_ci					     PAGE_KERNEL));
4968c2ecf20Sopenharmony_ci		}
4978c2ecf20Sopenharmony_ci	}
4988c2ecf20Sopenharmony_ci	return 0;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_cierr_alloc:
5018c2ecf20Sopenharmony_ci	panic("%s: Failed to allocate %lu bytes align=0x%lx nid=%d\n",
5028c2ecf20Sopenharmony_ci	      __func__, PAGE_SIZE, PAGE_SIZE, node);
5038c2ecf20Sopenharmony_ci	return -ENOMEM;
5048c2ecf20Sopenharmony_ci}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_cistruct memmap_init_callback_data {
5078c2ecf20Sopenharmony_ci	struct page *start;
5088c2ecf20Sopenharmony_ci	struct page *end;
5098c2ecf20Sopenharmony_ci	int nid;
5108c2ecf20Sopenharmony_ci	unsigned long zone;
5118c2ecf20Sopenharmony_ci};
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_cistatic int __meminit
5148c2ecf20Sopenharmony_civirtual_memmap_init(u64 start, u64 end, void *arg)
5158c2ecf20Sopenharmony_ci{
5168c2ecf20Sopenharmony_ci	struct memmap_init_callback_data *args;
5178c2ecf20Sopenharmony_ci	struct page *map_start, *map_end;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	args = (struct memmap_init_callback_data *) arg;
5208c2ecf20Sopenharmony_ci	map_start = vmem_map + (__pa(start) >> PAGE_SHIFT);
5218c2ecf20Sopenharmony_ci	map_end   = vmem_map + (__pa(end) >> PAGE_SHIFT);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	if (map_start < args->start)
5248c2ecf20Sopenharmony_ci		map_start = args->start;
5258c2ecf20Sopenharmony_ci	if (map_end > args->end)
5268c2ecf20Sopenharmony_ci		map_end = args->end;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	/*
5298c2ecf20Sopenharmony_ci	 * We have to initialize "out of bounds" struct page elements that fit completely
5308c2ecf20Sopenharmony_ci	 * on the same pages that were allocated for the "in bounds" elements because they
5318c2ecf20Sopenharmony_ci	 * may be referenced later (and found to be "reserved").
5328c2ecf20Sopenharmony_ci	 */
5338c2ecf20Sopenharmony_ci	map_start -= ((unsigned long) map_start & (PAGE_SIZE - 1)) / sizeof(struct page);
5348c2ecf20Sopenharmony_ci	map_end += ((PAGE_ALIGN((unsigned long) map_end) - (unsigned long) map_end)
5358c2ecf20Sopenharmony_ci		    / sizeof(struct page));
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	if (map_start < map_end)
5388c2ecf20Sopenharmony_ci		memmap_init_zone((unsigned long)(map_end - map_start),
5398c2ecf20Sopenharmony_ci				 args->nid, args->zone, page_to_pfn(map_start), page_to_pfn(map_end),
5408c2ecf20Sopenharmony_ci				 MEMINIT_EARLY, NULL, MIGRATE_MOVABLE);
5418c2ecf20Sopenharmony_ci	return 0;
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_civoid __meminit
5458c2ecf20Sopenharmony_ciarch_memmap_init (unsigned long size, int nid, unsigned long zone,
5468c2ecf20Sopenharmony_ci	     unsigned long start_pfn)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	if (!vmem_map) {
5498c2ecf20Sopenharmony_ci		memmap_init_zone(size, nid, zone, start_pfn, start_pfn + size,
5508c2ecf20Sopenharmony_ci				 MEMINIT_EARLY, NULL, MIGRATE_MOVABLE);
5518c2ecf20Sopenharmony_ci	} else {
5528c2ecf20Sopenharmony_ci		struct page *start;
5538c2ecf20Sopenharmony_ci		struct memmap_init_callback_data args;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci		start = pfn_to_page(start_pfn);
5568c2ecf20Sopenharmony_ci		args.start = start;
5578c2ecf20Sopenharmony_ci		args.end = start + size;
5588c2ecf20Sopenharmony_ci		args.nid = nid;
5598c2ecf20Sopenharmony_ci		args.zone = zone;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci		efi_memmap_walk(virtual_memmap_init, &args);
5628c2ecf20Sopenharmony_ci	}
5638c2ecf20Sopenharmony_ci}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_civoid __init memmap_init(void)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ciint
5708c2ecf20Sopenharmony_ciia64_pfn_valid (unsigned long pfn)
5718c2ecf20Sopenharmony_ci{
5728c2ecf20Sopenharmony_ci	char byte;
5738c2ecf20Sopenharmony_ci	struct page *pg = pfn_to_page(pfn);
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	return     (__get_user(byte, (char __user *) pg) == 0)
5768c2ecf20Sopenharmony_ci		&& ((((u64)pg & PAGE_MASK) == (((u64)(pg + 1) - 1) & PAGE_MASK))
5778c2ecf20Sopenharmony_ci			|| (__get_user(byte, (char __user *) (pg + 1) - 1) == 0));
5788c2ecf20Sopenharmony_ci}
5798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ia64_pfn_valid);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ciint __init find_largest_hole(u64 start, u64 end, void *arg)
5828c2ecf20Sopenharmony_ci{
5838c2ecf20Sopenharmony_ci	u64 *max_gap = arg;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	static u64 last_end = PAGE_OFFSET;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	/* NOTE: this algorithm assumes efi memmap table is ordered */
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	if (*max_gap < (start - last_end))
5908c2ecf20Sopenharmony_ci		*max_gap = start - last_end;
5918c2ecf20Sopenharmony_ci	last_end = end;
5928c2ecf20Sopenharmony_ci	return 0;
5938c2ecf20Sopenharmony_ci}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci#endif /* CONFIG_VIRTUAL_MEM_MAP */
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ciint __init register_active_ranges(u64 start, u64 len, int nid)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	u64 end = start + len;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci#ifdef CONFIG_KEXEC
6028c2ecf20Sopenharmony_ci	if (start > crashk_res.start && start < crashk_res.end)
6038c2ecf20Sopenharmony_ci		start = crashk_res.end;
6048c2ecf20Sopenharmony_ci	if (end > crashk_res.start && end < crashk_res.end)
6058c2ecf20Sopenharmony_ci		end = crashk_res.start;
6068c2ecf20Sopenharmony_ci#endif
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	if (start < end)
6098c2ecf20Sopenharmony_ci		memblock_add_node(__pa(start), end - start, nid);
6108c2ecf20Sopenharmony_ci	return 0;
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ciint
6148c2ecf20Sopenharmony_cifind_max_min_low_pfn (u64 start, u64 end, void *arg)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	unsigned long pfn_start, pfn_end;
6178c2ecf20Sopenharmony_ci#ifdef CONFIG_FLATMEM
6188c2ecf20Sopenharmony_ci	pfn_start = (PAGE_ALIGN(__pa(start))) >> PAGE_SHIFT;
6198c2ecf20Sopenharmony_ci	pfn_end = (PAGE_ALIGN(__pa(end - 1))) >> PAGE_SHIFT;
6208c2ecf20Sopenharmony_ci#else
6218c2ecf20Sopenharmony_ci	pfn_start = GRANULEROUNDDOWN(__pa(start)) >> PAGE_SHIFT;
6228c2ecf20Sopenharmony_ci	pfn_end = GRANULEROUNDUP(__pa(end - 1)) >> PAGE_SHIFT;
6238c2ecf20Sopenharmony_ci#endif
6248c2ecf20Sopenharmony_ci	min_low_pfn = min(min_low_pfn, pfn_start);
6258c2ecf20Sopenharmony_ci	max_low_pfn = max(max_low_pfn, pfn_end);
6268c2ecf20Sopenharmony_ci	return 0;
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci/*
6308c2ecf20Sopenharmony_ci * Boot command-line option "nolwsys" can be used to disable the use of any light-weight
6318c2ecf20Sopenharmony_ci * system call handler.  When this option is in effect, all fsyscalls will end up bubbling
6328c2ecf20Sopenharmony_ci * down into the kernel and calling the normal (heavy-weight) syscall handler.  This is
6338c2ecf20Sopenharmony_ci * useful for performance testing, but conceivably could also come in handy for debugging
6348c2ecf20Sopenharmony_ci * purposes.
6358c2ecf20Sopenharmony_ci */
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_cistatic int nolwsys __initdata;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_cistatic int __init
6408c2ecf20Sopenharmony_cinolwsys_setup (char *s)
6418c2ecf20Sopenharmony_ci{
6428c2ecf20Sopenharmony_ci	nolwsys = 1;
6438c2ecf20Sopenharmony_ci	return 1;
6448c2ecf20Sopenharmony_ci}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci__setup("nolwsys", nolwsys_setup);
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_civoid __init
6498c2ecf20Sopenharmony_cimem_init (void)
6508c2ecf20Sopenharmony_ci{
6518c2ecf20Sopenharmony_ci	int i;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	BUG_ON(PTRS_PER_PGD * sizeof(pgd_t) != PAGE_SIZE);
6548c2ecf20Sopenharmony_ci	BUG_ON(PTRS_PER_PMD * sizeof(pmd_t) != PAGE_SIZE);
6558c2ecf20Sopenharmony_ci	BUG_ON(PTRS_PER_PTE * sizeof(pte_t) != PAGE_SIZE);
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	/*
6588c2ecf20Sopenharmony_ci	 * This needs to be called _after_ the command line has been parsed but
6598c2ecf20Sopenharmony_ci	 * _before_ any drivers that may need the PCI DMA interface are
6608c2ecf20Sopenharmony_ci	 * initialized or bootmem has been freed.
6618c2ecf20Sopenharmony_ci	 */
6628c2ecf20Sopenharmony_ci#ifdef CONFIG_INTEL_IOMMU
6638c2ecf20Sopenharmony_ci	detect_intel_iommu();
6648c2ecf20Sopenharmony_ci	if (!iommu_detected)
6658c2ecf20Sopenharmony_ci#endif
6668c2ecf20Sopenharmony_ci#ifdef CONFIG_SWIOTLB
6678c2ecf20Sopenharmony_ci		swiotlb_init(1);
6688c2ecf20Sopenharmony_ci#endif
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci#ifdef CONFIG_FLATMEM
6718c2ecf20Sopenharmony_ci	BUG_ON(!mem_map);
6728c2ecf20Sopenharmony_ci#endif
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	set_max_mapnr(max_low_pfn);
6758c2ecf20Sopenharmony_ci	high_memory = __va(max_low_pfn * PAGE_SIZE);
6768c2ecf20Sopenharmony_ci	memblock_free_all();
6778c2ecf20Sopenharmony_ci	mem_init_print_info(NULL);
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	/*
6808c2ecf20Sopenharmony_ci	 * For fsyscall entrpoints with no light-weight handler, use the ordinary
6818c2ecf20Sopenharmony_ci	 * (heavy-weight) handler, but mark it by setting bit 0, so the fsyscall entry
6828c2ecf20Sopenharmony_ci	 * code can tell them apart.
6838c2ecf20Sopenharmony_ci	 */
6848c2ecf20Sopenharmony_ci	for (i = 0; i < NR_syscalls; ++i) {
6858c2ecf20Sopenharmony_ci		extern unsigned long fsyscall_table[NR_syscalls];
6868c2ecf20Sopenharmony_ci		extern unsigned long sys_call_table[NR_syscalls];
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci		if (!fsyscall_table[i] || nolwsys)
6898c2ecf20Sopenharmony_ci			fsyscall_table[i] = sys_call_table[i] | 1;
6908c2ecf20Sopenharmony_ci	}
6918c2ecf20Sopenharmony_ci	setup_gate();
6928c2ecf20Sopenharmony_ci}
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci#ifdef CONFIG_MEMORY_HOTPLUG
6958c2ecf20Sopenharmony_ciint arch_add_memory(int nid, u64 start, u64 size,
6968c2ecf20Sopenharmony_ci		    struct mhp_params *params)
6978c2ecf20Sopenharmony_ci{
6988c2ecf20Sopenharmony_ci	unsigned long start_pfn = start >> PAGE_SHIFT;
6998c2ecf20Sopenharmony_ci	unsigned long nr_pages = size >> PAGE_SHIFT;
7008c2ecf20Sopenharmony_ci	int ret;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(params->pgprot.pgprot != PAGE_KERNEL.pgprot))
7038c2ecf20Sopenharmony_ci		return -EINVAL;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	ret = __add_pages(nid, start_pfn, nr_pages, params);
7068c2ecf20Sopenharmony_ci	if (ret)
7078c2ecf20Sopenharmony_ci		printk("%s: Problem encountered in __add_pages() as ret=%d\n",
7088c2ecf20Sopenharmony_ci		       __func__,  ret);
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	return ret;
7118c2ecf20Sopenharmony_ci}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_civoid arch_remove_memory(int nid, u64 start, u64 size,
7148c2ecf20Sopenharmony_ci			struct vmem_altmap *altmap)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	unsigned long start_pfn = start >> PAGE_SHIFT;
7178c2ecf20Sopenharmony_ci	unsigned long nr_pages = size >> PAGE_SHIFT;
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	__remove_pages(start_pfn, nr_pages, altmap);
7208c2ecf20Sopenharmony_ci}
7218c2ecf20Sopenharmony_ci#endif
722