^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Page table allocation functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright IBM Corp. 2016
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/sysctl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <asm/mmu_context.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/pgalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/gmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/tlb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/tlbflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #ifdef CONFIG_PGSTE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) int page_table_allocate_pgste = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) EXPORT_SYMBOL(page_table_allocate_pgste);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static struct ctl_table page_table_sysctl[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) .procname = "allocate_pgste",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) .data = &page_table_allocate_pgste,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) .maxlen = sizeof(int),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) .mode = S_IRUGO | S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) .proc_handler = proc_dointvec_minmax,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) .extra1 = SYSCTL_ZERO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) .extra2 = SYSCTL_ONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static struct ctl_table page_table_sysctl_dir[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) .procname = "vm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) .maxlen = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) .mode = 0555,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) .child = page_table_sysctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static int __init page_table_register_sysctl(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) return register_sysctl_table(page_table_sysctl_dir) ? 0 : -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) __initcall(page_table_register_sysctl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #endif /* CONFIG_PGSTE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) unsigned long *crst_table_alloc(struct mm_struct *mm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct page *page = alloc_pages(GFP_KERNEL, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (!page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) arch_set_page_dat(page, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return (unsigned long *) page_to_phys(page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) void crst_table_free(struct mm_struct *mm, unsigned long *table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) free_pages((unsigned long) table, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static void __crst_table_upgrade(void *arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct mm_struct *mm = arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /* we must change all active ASCEs to avoid the creation of new TLBs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (current->active_mm == mm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) S390_lowcore.user_asce = mm->context.asce;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (current->thread.mm_segment == USER_DS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) __ctl_load(S390_lowcore.user_asce, 1, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /* Mark user-ASCE present in CR1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) clear_cpu_flag(CIF_ASCE_PRIMARY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (current->thread.mm_segment == USER_DS_SACF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) __ctl_load(S390_lowcore.user_asce, 7, 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) /* enable_sacf_uaccess does all or nothing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) WARN_ON(!test_cpu_flag(CIF_ASCE_SECONDARY));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) __tlb_flush_local();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) int crst_table_upgrade(struct mm_struct *mm, unsigned long end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) unsigned long *pgd = NULL, *p4d = NULL, *__pgd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) unsigned long asce_limit = mm->context.asce_limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) /* upgrade should only happen from 3 to 4, 3 to 5, or 4 to 5 levels */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) VM_BUG_ON(asce_limit < _REGION2_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (end <= asce_limit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (asce_limit == _REGION2_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) p4d = crst_table_alloc(mm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (unlikely(!p4d))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) goto err_p4d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) crst_table_init(p4d, _REGION2_ENTRY_EMPTY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (end > _REGION1_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) pgd = crst_table_alloc(mm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (unlikely(!pgd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) goto err_pgd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) crst_table_init(pgd, _REGION1_ENTRY_EMPTY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) spin_lock_bh(&mm->page_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * This routine gets called with mmap_lock lock held and there is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * no reason to optimize for the case of otherwise. However, if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * that would ever change, the below check will let us know.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) VM_BUG_ON(asce_limit != mm->context.asce_limit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (p4d) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) __pgd = (unsigned long *) mm->pgd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) p4d_populate(mm, (p4d_t *) p4d, (pud_t *) __pgd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) mm->pgd = (pgd_t *) p4d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) mm->context.asce_limit = _REGION1_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) _ASCE_USER_BITS | _ASCE_TYPE_REGION2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) mm_inc_nr_puds(mm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (pgd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) __pgd = (unsigned long *) mm->pgd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) pgd_populate(mm, (pgd_t *) pgd, (p4d_t *) __pgd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) mm->pgd = (pgd_t *) pgd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) mm->context.asce_limit = TASK_SIZE_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) mm->context.asce = __pa(mm->pgd) | _ASCE_TABLE_LENGTH |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) _ASCE_USER_BITS | _ASCE_TYPE_REGION1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) spin_unlock_bh(&mm->page_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) on_each_cpu(__crst_table_upgrade, mm, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) err_pgd:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) crst_table_free(mm, p4d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) err_p4d:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) static inline unsigned int atomic_xor_bits(atomic_t *v, unsigned int bits)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) unsigned int old, new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) old = atomic_read(v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) new = old ^ bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) } while (atomic_cmpxchg(v, old, new) != old);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) #ifdef CONFIG_PGSTE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) struct page *page_table_alloc_pgste(struct mm_struct *mm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) struct page *page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) u64 *table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) page = alloc_page(GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (page) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) table = (u64 *)page_to_phys(page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) memset64(table, _PAGE_INVALID, PTRS_PER_PTE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) memset64(table + PTRS_PER_PTE, 0, PTRS_PER_PTE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) void page_table_free_pgste(struct page *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) __free_page(page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) #endif /* CONFIG_PGSTE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * page table entry allocation/free routines.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) unsigned long *page_table_alloc(struct mm_struct *mm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) unsigned long *table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) struct page *page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) unsigned int mask, bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) /* Try to get a fragment of a 4K page as a 2K page table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (!mm_alloc_pgste(mm)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) table = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) spin_lock_bh(&mm->context.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (!list_empty(&mm->context.pgtable_list)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) page = list_first_entry(&mm->context.pgtable_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct page, lru);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) mask = atomic_read(&page->_refcount) >> 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) mask = (mask | (mask >> 4)) & 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) if (mask != 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) table = (unsigned long *) page_to_phys(page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) bit = mask & 1; /* =1 -> second 2K */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) if (bit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) table += PTRS_PER_PTE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) atomic_xor_bits(&page->_refcount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 1U << (bit + 24));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) list_del(&page->lru);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) spin_unlock_bh(&mm->context.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) if (table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) return table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) /* Allocate a fresh page */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) page = alloc_page(GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (!page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (!pgtable_pte_page_ctor(page)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) __free_page(page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) arch_set_page_dat(page, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) /* Initialize page table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) table = (unsigned long *) page_to_phys(page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) if (mm_alloc_pgste(mm)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) /* Return 4K page table with PGSTEs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) atomic_xor_bits(&page->_refcount, 3 << 24);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) memset64((u64 *)table, _PAGE_INVALID, PTRS_PER_PTE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) memset64((u64 *)table + PTRS_PER_PTE, 0, PTRS_PER_PTE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) /* Return the first 2K fragment of the page */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) atomic_xor_bits(&page->_refcount, 1 << 24);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) memset64((u64 *)table, _PAGE_INVALID, 2 * PTRS_PER_PTE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) spin_lock_bh(&mm->context.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) list_add(&page->lru, &mm->context.pgtable_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) spin_unlock_bh(&mm->context.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) void page_table_free(struct mm_struct *mm, unsigned long *table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) struct page *page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) unsigned int bit, mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (!mm_alloc_pgste(mm)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) /* Free 2K page table fragment of a 4K page */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) bit = (__pa(table) & ~PAGE_MASK)/(PTRS_PER_PTE*sizeof(pte_t));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) spin_lock_bh(&mm->context.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) mask = atomic_xor_bits(&page->_refcount, 0x11U << (bit + 24));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) mask >>= 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (mask & 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) list_add(&page->lru, &mm->context.pgtable_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) list_del(&page->lru);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) spin_unlock_bh(&mm->context.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) mask = atomic_xor_bits(&page->_refcount, 0x10U << (bit + 24));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) mask >>= 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (mask != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) atomic_xor_bits(&page->_refcount, 3U << 24);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) pgtable_pte_page_dtor(page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) __free_page(page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) void page_table_free_rcu(struct mmu_gather *tlb, unsigned long *table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) unsigned long vmaddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) struct mm_struct *mm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) struct page *page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) unsigned int bit, mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) mm = tlb->mm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) if (mm_alloc_pgste(mm)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) gmap_unlink(mm, table, vmaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) table = (unsigned long *) (__pa(table) | 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) tlb_remove_table(tlb, table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) bit = (__pa(table) & ~PAGE_MASK) / (PTRS_PER_PTE*sizeof(pte_t));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) spin_lock_bh(&mm->context.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) mask = atomic_xor_bits(&page->_refcount, 0x11U << (bit + 24));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) mask >>= 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) if (mask & 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) list_add_tail(&page->lru, &mm->context.pgtable_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) list_del(&page->lru);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) spin_unlock_bh(&mm->context.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) table = (unsigned long *) (__pa(table) | (1U << bit));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) tlb_remove_table(tlb, table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) void __tlb_remove_table(void *_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) unsigned int mask = (unsigned long) _table & 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) void *table = (void *)((unsigned long) _table ^ mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) struct page *page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) switch (mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) case 0: /* pmd, pud, or p4d */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) free_pages((unsigned long) table, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) case 1: /* lower 2K of a 4K page table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) case 2: /* higher 2K of a 4K page table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) mask = atomic_xor_bits(&page->_refcount, mask << (4 + 24));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) mask >>= 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (mask != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) case 3: /* 4K page table with pgstes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if (mask & 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) atomic_xor_bits(&page->_refcount, 3 << 24);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) pgtable_pte_page_dtor(page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) __free_page(page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) * Base infrastructure required to generate basic asces, region, segment,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) * and page tables that do not make use of enhanced features like EDAT1.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) static struct kmem_cache *base_pgt_cache;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) static unsigned long base_pgt_alloc(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) u64 *table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) table = kmem_cache_alloc(base_pgt_cache, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) if (table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) memset64(table, _PAGE_INVALID, PTRS_PER_PTE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) return (unsigned long) table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) static void base_pgt_free(unsigned long table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) kmem_cache_free(base_pgt_cache, (void *) table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) static unsigned long base_crst_alloc(unsigned long val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) unsigned long table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) table = __get_free_pages(GFP_KERNEL, CRST_ALLOC_ORDER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) if (table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) crst_table_init((unsigned long *)table, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) return table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) static void base_crst_free(unsigned long table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) free_pages(table, CRST_ALLOC_ORDER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) #define BASE_ADDR_END_FUNC(NAME, SIZE) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) static inline unsigned long base_##NAME##_addr_end(unsigned long addr, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) unsigned long end) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) unsigned long next = (addr + (SIZE)) & ~((SIZE) - 1); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) return (next - 1) < (end - 1) ? next : end; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) BASE_ADDR_END_FUNC(page, _PAGE_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) BASE_ADDR_END_FUNC(segment, _SEGMENT_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) BASE_ADDR_END_FUNC(region3, _REGION3_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) BASE_ADDR_END_FUNC(region2, _REGION2_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) BASE_ADDR_END_FUNC(region1, _REGION1_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) static inline unsigned long base_lra(unsigned long address)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) unsigned long real;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) " lra %0,0(%1)\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) : "=d" (real) : "a" (address) : "cc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) return real;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) static int base_page_walk(unsigned long origin, unsigned long addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) unsigned long end, int alloc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) unsigned long *pte, next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) if (!alloc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) pte = (unsigned long *) origin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) pte += (addr & _PAGE_INDEX) >> _PAGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) next = base_page_addr_end(addr, end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) *pte = base_lra(addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) } while (pte++, addr = next, addr < end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) static int base_segment_walk(unsigned long origin, unsigned long addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) unsigned long end, int alloc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) unsigned long *ste, next, table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) ste = (unsigned long *) origin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) ste += (addr & _SEGMENT_INDEX) >> _SEGMENT_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) next = base_segment_addr_end(addr, end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) if (*ste & _SEGMENT_ENTRY_INVALID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) if (!alloc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) table = base_pgt_alloc();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) if (!table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) *ste = table | _SEGMENT_ENTRY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) table = *ste & _SEGMENT_ENTRY_ORIGIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) rc = base_page_walk(table, addr, next, alloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) if (!alloc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) base_pgt_free(table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) cond_resched();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) } while (ste++, addr = next, addr < end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) static int base_region3_walk(unsigned long origin, unsigned long addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) unsigned long end, int alloc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) unsigned long *rtte, next, table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) rtte = (unsigned long *) origin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) rtte += (addr & _REGION3_INDEX) >> _REGION3_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) next = base_region3_addr_end(addr, end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) if (*rtte & _REGION_ENTRY_INVALID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) if (!alloc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) table = base_crst_alloc(_SEGMENT_ENTRY_EMPTY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) if (!table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) *rtte = table | _REGION3_ENTRY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) table = *rtte & _REGION_ENTRY_ORIGIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) rc = base_segment_walk(table, addr, next, alloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) if (!alloc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) base_crst_free(table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) } while (rtte++, addr = next, addr < end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) static int base_region2_walk(unsigned long origin, unsigned long addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) unsigned long end, int alloc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) unsigned long *rste, next, table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) rste = (unsigned long *) origin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) rste += (addr & _REGION2_INDEX) >> _REGION2_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) next = base_region2_addr_end(addr, end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) if (*rste & _REGION_ENTRY_INVALID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) if (!alloc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) table = base_crst_alloc(_REGION3_ENTRY_EMPTY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) if (!table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) *rste = table | _REGION2_ENTRY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) table = *rste & _REGION_ENTRY_ORIGIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) rc = base_region3_walk(table, addr, next, alloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) if (!alloc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) base_crst_free(table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) } while (rste++, addr = next, addr < end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) static int base_region1_walk(unsigned long origin, unsigned long addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) unsigned long end, int alloc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) unsigned long *rfte, next, table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) rfte = (unsigned long *) origin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) rfte += (addr & _REGION1_INDEX) >> _REGION1_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) next = base_region1_addr_end(addr, end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) if (*rfte & _REGION_ENTRY_INVALID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) if (!alloc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) table = base_crst_alloc(_REGION2_ENTRY_EMPTY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) if (!table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) *rfte = table | _REGION1_ENTRY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) table = *rfte & _REGION_ENTRY_ORIGIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) rc = base_region2_walk(table, addr, next, alloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) if (!alloc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) base_crst_free(table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) } while (rfte++, addr = next, addr < end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) * base_asce_free - free asce and tables returned from base_asce_alloc()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) * @asce: asce to be freed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) * Frees all region, segment, and page tables that were allocated with a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) * corresponding base_asce_alloc() call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) void base_asce_free(unsigned long asce)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) unsigned long table = asce & _ASCE_ORIGIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) if (!asce)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) switch (asce & _ASCE_TYPE_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) case _ASCE_TYPE_SEGMENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) base_segment_walk(table, 0, _REGION3_SIZE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) case _ASCE_TYPE_REGION3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) base_region3_walk(table, 0, _REGION2_SIZE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) case _ASCE_TYPE_REGION2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) base_region2_walk(table, 0, _REGION1_SIZE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) case _ASCE_TYPE_REGION1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) base_region1_walk(table, 0, TASK_SIZE_MAX, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) base_crst_free(table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) static int base_pgt_cache_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) static DEFINE_MUTEX(base_pgt_cache_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) unsigned long sz = _PAGE_TABLE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) if (base_pgt_cache)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) mutex_lock(&base_pgt_cache_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) if (!base_pgt_cache)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) base_pgt_cache = kmem_cache_create("base_pgt", sz, sz, 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) mutex_unlock(&base_pgt_cache_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) return base_pgt_cache ? 0 : -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) * base_asce_alloc - create kernel mapping without enhanced DAT features
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) * @addr: virtual start address of kernel mapping
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) * @num_pages: number of consecutive pages
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) * Generate an asce, including all required region, segment and page tables,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) * that can be used to access the virtual kernel mapping. The difference is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) * that the returned asce does not make use of any enhanced DAT features like
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) * e.g. large pages. This is required for some I/O functions that pass an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) * asce, like e.g. some service call requests.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) * Note: the returned asce may NEVER be attached to any cpu. It may only be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) * used for I/O requests. tlb entries that might result because the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) * asce was attached to a cpu won't be cleared.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) unsigned long base_asce_alloc(unsigned long addr, unsigned long num_pages)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) unsigned long asce, table, end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) if (base_pgt_cache_init())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) end = addr + num_pages * PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (end <= _REGION3_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) table = base_crst_alloc(_SEGMENT_ENTRY_EMPTY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) if (!table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) rc = base_segment_walk(table, addr, end, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) asce = table | _ASCE_TYPE_SEGMENT | _ASCE_TABLE_LENGTH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) } else if (end <= _REGION2_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) table = base_crst_alloc(_REGION3_ENTRY_EMPTY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) if (!table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) rc = base_region3_walk(table, addr, end, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) asce = table | _ASCE_TYPE_REGION3 | _ASCE_TABLE_LENGTH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) } else if (end <= _REGION1_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) table = base_crst_alloc(_REGION2_ENTRY_EMPTY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) if (!table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) rc = base_region2_walk(table, addr, end, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) asce = table | _ASCE_TYPE_REGION2 | _ASCE_TABLE_LENGTH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) table = base_crst_alloc(_REGION1_ENTRY_EMPTY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) if (!table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) rc = base_region1_walk(table, addr, end, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) asce = table | _ASCE_TYPE_REGION1 | _ASCE_TABLE_LENGTH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) base_asce_free(asce);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) asce = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) return asce;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) }