1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. 3 4 #include <linux/bug.h> 5 #include <linux/module.h> 6 #include <linux/init.h> 7 #include <linux/signal.h> 8 #include <linux/sched.h> 9 #include <linux/kernel.h> 10 #include <linux/errno.h> 11 #include <linux/string.h> 12 #include <linux/types.h> 13 #include <linux/pagemap.h> 14 #include <linux/ptrace.h> 15 #include <linux/mman.h> 16 #include <linux/mm.h> 17 #include <linux/highmem.h> 18 #include <linux/memblock.h> 19 #include <linux/swap.h> 20 #include <linux/proc_fs.h> 21 #include <linux/pfn.h> 22 #include <linux/initrd.h> 23 24 #include <asm/setup.h> 25 #include <asm/cachectl.h> 26 #include <asm/dma.h> 27 #include <asm/pgalloc.h> 28 #include <asm/mmu_context.h> 29 #include <asm/sections.h> 30 #include <asm/tlb.h> 31 #include <asm/cacheflush.h> 32 33 #define PTRS_KERN_TABLE \ 34 ((PTRS_PER_PGD - USER_PTRS_PER_PGD) * PTRS_PER_PTE) 35 36 pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned_bss; 37 pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned_bss; 38 pte_t kernel_pte_tables[PTRS_KERN_TABLE] __page_aligned_bss; 39 40 EXPORT_SYMBOL(invalid_pte_table); 41 42 void free_initmem(void) 43 { 44 free_initmem_default(-1); 45 } 46 47 void pgd_init(unsigned long *p) 48 { 49 int i; 50 51 for (i = 0; i < PTRS_PER_PGD; i++) 52 p[i] = __pa(invalid_pte_table); 53 54 flush_tlb_all(); 55 local_icache_inv_all(NULL); 56 } 57 58 void __init mmu_init(unsigned long min_pfn, unsigned long max_pfn) 59 { 60 int i; 61 62 for (i = 0; i < USER_PTRS_PER_PGD; i++) 63 swapper_pg_dir[i].pgd = __pa(invalid_pte_table); 64 65 for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++) 66 swapper_pg_dir[i].pgd = 67 __pa(kernel_pte_tables + (PTRS_PER_PTE * (i - USER_PTRS_PER_PGD))); 68 69 for (i = 0; i < PTRS_KERN_TABLE; i++) 70 set_pte(&kernel_pte_tables[i], __pte(_PAGE_GLOBAL)); 71 72 for (i = min_pfn; i < max_pfn; i++) 73 set_pte(&kernel_pte_tables[i - PFN_DOWN(va_pa_offset)], pfn_pte(i, PAGE_KERNEL)); 74 75 flush_tlb_all(); 76 local_icache_inv_all(NULL); 77 78 /* Setup page mask to 4k */ 79 write_mmu_pagemask(0); 80 81 setup_pgd(swapper_pg_dir, 0); 82 } 83 84 void __init fixrange_init(unsigned long start, unsigned long end, 85 pgd_t *pgd_base) 86 { 87 pgd_t *pgd; 88 pud_t *pud; 89 pmd_t *pmd; 90 pte_t *pte; 91 int i, j, k; 92 unsigned long vaddr; 93 94 vaddr = start; 95 i = pgd_index(vaddr); 96 j = pud_index(vaddr); 97 k = pmd_index(vaddr); 98 pgd = pgd_base + i; 99 100 for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) { 101 pud = (pud_t *)pgd; 102 for ( ; (j < PTRS_PER_PUD) && (vaddr != end); pud++, j++) { 103 pmd = (pmd_t *)pud; 104 for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) { 105 if (pmd_none(*pmd)) { 106 pte = (pte_t *) memblock_alloc_low(PAGE_SIZE, PAGE_SIZE); 107 if (!pte) 108 panic("%s: Failed to allocate %lu bytes align=%lx\n", 109 __func__, PAGE_SIZE, 110 PAGE_SIZE); 111 112 set_pmd(pmd, __pmd(__pa(pte))); 113 BUG_ON(pte != pte_offset_kernel(pmd, 0)); 114 } 115 vaddr += PMD_SIZE; 116 } 117 k = 0; 118 } 119 j = 0; 120 } 121 } 122 123 void __init fixaddr_init(void) 124 { 125 unsigned long vaddr; 126 127 vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; 128 fixrange_init(vaddr, vaddr + PMD_SIZE, swapper_pg_dir); 129 } 130 131 static const pgprot_t protection_map[16] = { 132 [VM_NONE] = PAGE_NONE, 133 [VM_READ] = PAGE_READ, 134 [VM_WRITE] = PAGE_READ, 135 [VM_WRITE | VM_READ] = PAGE_READ, 136 [VM_EXEC] = PAGE_READ, 137 [VM_EXEC | VM_READ] = PAGE_READ, 138 [VM_EXEC | VM_WRITE] = PAGE_READ, 139 [VM_EXEC | VM_WRITE | VM_READ] = PAGE_READ, 140 [VM_SHARED] = PAGE_NONE, 141 [VM_SHARED | VM_READ] = PAGE_READ, 142 [VM_SHARED | VM_WRITE] = PAGE_WRITE, 143 [VM_SHARED | VM_WRITE | VM_READ] = PAGE_WRITE, 144 [VM_SHARED | VM_EXEC] = PAGE_READ, 145 [VM_SHARED | VM_EXEC | VM_READ] = PAGE_READ, 146 [VM_SHARED | VM_EXEC | VM_WRITE] = PAGE_WRITE, 147 [VM_SHARED | VM_EXEC | VM_WRITE | VM_READ] = PAGE_WRITE 148 }; 149 DECLARE_VM_GET_PAGE_PROT 150