1 /* 2 * s390x page table definitions and functions 3 * 4 * Copyright (c) 2017 Red Hat Inc 5 * 6 * Authors: 7 * David Hildenbrand <david@redhat.com> 8 * 9 * This code is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU Library General Public License version 2. 11 */ 12 #ifndef _ASMS390X_PGTABLE_H_ 13 #define _ASMS390X_PGTABLE_H_ 14 15 #include <asm/page.h> 16 #include <alloc_page.h> 17 18 #define ASCE_ORIGIN 0xfffffffffffff000UL 19 #define ASCE_G 0x0000000000000200UL 20 #define ASCE_P 0x0000000000000100UL 21 #define ASCE_S 0x0000000000000080UL 22 #define ASCE_X 0x0000000000000040UL 23 #define ASCE_R 0x0000000000000020UL 24 #define ASCE_DT 0x000000000000000cUL 25 #define ASCE_TL 0x0000000000000003UL 26 27 #define ASCE_DT_REGION1 0x000000000000000cUL 28 #define ASCE_DT_REGION2 0x0000000000000008UL 29 #define ASCE_DT_REGION3 0x0000000000000004UL 30 #define ASCE_DT_SEGMENT 0x0000000000000000UL 31 32 #define REGION_TABLE_ORDER 2 33 #define REGION_TABLE_ENTRIES 2048 34 #define REGION_TABLE_LENGTH 3 35 36 #define REGION1_SHIFT 53 37 #define REGION2_SHIFT 42 38 #define REGION3_SHIFT 31 39 40 #define REGION_ENTRY_ORIGIN 0xfffffffffffff000UL 41 #define REGION_ENTRY_P 0x0000000000000200UL 42 #define REGION_ENTRY_TF 0x00000000000000c0UL 43 #define REGION_ENTRY_I 0x0000000000000020UL 44 #define REGION_ENTRY_TT 0x000000000000000cUL 45 #define REGION_ENTRY_TL 0x0000000000000003UL 46 47 #define REGION_ENTRY_TT_REGION1 0x000000000000000cUL 48 #define REGION_ENTRY_TT_REGION2 0x0000000000000008UL 49 #define REGION_ENTRY_TT_REGION3 0x0000000000000004UL 50 51 #define REGION3_ENTRY_RFAA 0xffffffff80000000UL 52 #define REGION3_ENTRY_AV 0x0000000000010000UL 53 #define REGION3_ENTRY_ACC 0x000000000000f000UL 54 #define REGION3_ENTRY_F 0x0000000000000800UL 55 #define REGION3_ENTRY_FC 0x0000000000000400UL 56 #define REGION3_ENTRY_IEP 0x0000000000000100UL 57 #define REGION3_ENTRY_CR 0x0000000000000010UL 58 59 #define SEGMENT_TABLE_ORDER 2 60 #define SEGMENT_TABLE_ENTRIES 2048 61 #define SEGMENT_TABLE_LENGTH 3 62 #define SEGMENT_SHIFT 20 63 64 #define SEGMENT_ENTRY_ORIGIN 0xfffffffffffff800UL 65 #define SEGMENT_ENTRY_SFAA 0xfffffffffff80000UL 66 #define SEGMENT_ENTRY_AV 0x0000000000010000UL 67 #define SEGMENT_ENTRY_ACC 0x000000000000f000UL 68 #define SEGMENT_ENTRY_F 0x0000000000000800UL 69 #define SEGMENT_ENTRY_FC 0x0000000000000400UL 70 #define SEGMENT_ENTRY_P 0x0000000000000200UL 71 #define SEGMENT_ENTRY_IEP 0x0000000000000100UL 72 #define SEGMENT_ENTRY_I 0x0000000000000020UL 73 #define SEGMENT_ENTRY_CS 0x0000000000000010UL 74 #define SEGMENT_ENTRY_TT 0x000000000000000cUL 75 76 #define SEGMENT_ENTRY_TT_REGION1 0x000000000000000cUL 77 #define SEGMENT_ENTRY_TT_REGION2 0x0000000000000008UL 78 #define SEGMENT_ENTRY_TT_REGION3 0x0000000000000004UL 79 #define SEGMENT_ENTRY_TT_SEGMENT 0x0000000000000000UL 80 81 #define PAGE_TABLE_ORDER 0 82 #define PAGE_TABLE_ENTRIES 256 83 84 #define PAGE_ENTRY_I 0x0000000000000400UL 85 #define PAGE_ENTRY_P 0x0000000000000200UL 86 #define PAGE_ENTRY_IEP 0x0000000000000100UL 87 88 #define PTRS_PER_PGD REGION_TABLE_ENTRIES 89 #define PTRS_PER_P4D REGION_TABLE_ENTRIES 90 #define PTRS_PER_PUD REGION_TABLE_ENTRIES 91 #define PTRS_PER_PMD SEGMENT_TABLE_ENTRIES 92 #define PTRS_PER_PTE PAGE_TABLE_ENTRIES 93 94 #define PGDIR_SHIFT REGION1_SHIFT 95 #define P4D_SHIFT REGION2_SHIFT 96 #define PUD_SHIFT REGION3_SHIFT 97 #define PMD_SHIFT SEGMENT_SHIFT 98 99 #define pgd_none(entry) (pgd_val(entry) & REGION_ENTRY_I) 100 #define p4d_none(entry) (p4d_val(entry) & REGION_ENTRY_I) 101 #define pud_none(entry) (pud_val(entry) & REGION_ENTRY_I) 102 #define pmd_none(entry) (pmd_val(entry) & SEGMENT_ENTRY_I) 103 #define pte_none(entry) (pte_val(entry) & PAGE_ENTRY_I) 104 105 #define pgd_addr(entry) __va(pgd_val(entry) & REGION_ENTRY_ORIGIN) 106 #define p4d_addr(entry) __va(p4d_val(entry) & REGION_ENTRY_ORIGIN) 107 #define pud_addr(entry) __va(pud_val(entry) & REGION_ENTRY_ORIGIN) 108 #define pmd_addr(entry) __va(pmd_val(entry) & SEGMENT_ENTRY_ORIGIN) 109 #define pte_addr(entry) __va(pte_val(entry) & PAGE_MASK) 110 111 #define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) 112 #define p4d_index(addr) (((addr) >> P4D_SHIFT) & (PTRS_PER_P4D - 1)) 113 #define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)) 114 #define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) 115 #define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) 116 117 #define pgd_offset(table, addr) ((pgd_t *)(table) + pgd_index(addr)) 118 #define p4d_offset(pgd, addr) ((p4d_t *)pgd_addr(*(pgd)) + p4d_index(addr)) 119 #define pud_offset(p4d, addr) ((pud_t *)p4d_addr(*(p4d)) + pud_index(addr)) 120 #define pmd_offset(pud, addr) ((pmd_t *)pud_addr(*(pud)) + pmd_index(addr)) 121 #define pte_offset(pmd, addr) ((pte_t *)pmd_addr(*(pmd)) + pte_index(addr)) 122 123 static inline pgd_t *pgd_alloc_one(void) 124 { 125 pgd_t *pgd = alloc_pages(REGION_TABLE_ORDER); 126 int i; 127 128 for (i = 0; i < REGION_TABLE_ENTRIES; i++) 129 pgd_val(pgd[i]) = REGION_ENTRY_TT_REGION1 | REGION_ENTRY_I; 130 return pgd; 131 } 132 133 static inline p4d_t *p4d_alloc_one(void) 134 { 135 p4d_t *p4d = alloc_pages(REGION_TABLE_ORDER); 136 int i; 137 138 for (i = 0; i < REGION_TABLE_ENTRIES; i++) 139 p4d_val(p4d[i]) = REGION_ENTRY_TT_REGION2 | REGION_ENTRY_I; 140 return p4d; 141 } 142 143 static inline p4d_t *p4d_alloc(pgd_t *pgd, unsigned long addr) 144 { 145 if (pgd_none(*pgd)) { 146 p4d_t *p4d = p4d_alloc_one(); 147 pgd_val(*pgd) = __pa(p4d) | REGION_ENTRY_TT_REGION1 | 148 REGION_TABLE_LENGTH; 149 } 150 return p4d_offset(pgd, addr); 151 } 152 153 static inline pud_t *pud_alloc_one(void) 154 { 155 pud_t *pud = alloc_pages(REGION_TABLE_ORDER); 156 int i; 157 158 for (i = 0; i < REGION_TABLE_ENTRIES; i++) 159 pud_val(pud[i]) = REGION_ENTRY_TT_REGION3 | REGION_ENTRY_I; 160 return pud; 161 } 162 163 static inline pud_t *pud_alloc(p4d_t *p4d, unsigned long addr) 164 { 165 if (p4d_none(*p4d)) { 166 pud_t *pud = pud_alloc_one(); 167 p4d_val(*p4d) = __pa(pud) | REGION_ENTRY_TT_REGION2 | 168 REGION_TABLE_LENGTH; 169 } 170 return pud_offset(p4d, addr); 171 } 172 173 static inline pmd_t *pmd_alloc_one(void) 174 { 175 pmd_t *pmd = alloc_pages(SEGMENT_TABLE_ORDER); 176 int i; 177 178 for (i = 0; i < SEGMENT_TABLE_ENTRIES; i++) 179 pmd_val(pmd[i]) = SEGMENT_ENTRY_TT_SEGMENT | SEGMENT_ENTRY_I; 180 return pmd; 181 } 182 183 static inline pmd_t *pmd_alloc(pud_t *pud, unsigned long addr) 184 { 185 if (pud_none(*pud)) { 186 pmd_t *pmd = pmd_alloc_one(); 187 pud_val(*pud) = __pa(pmd) | REGION_ENTRY_TT_REGION3 | 188 REGION_TABLE_LENGTH; 189 } 190 return pmd_offset(pud, addr); 191 } 192 193 static inline pte_t *pte_alloc_one(void) 194 { 195 pte_t *pte = alloc_pages(PAGE_TABLE_ORDER); 196 int i; 197 198 for (i = 0; i < PAGE_TABLE_ENTRIES; i++) 199 pte_val(pte[i]) = PAGE_ENTRY_I; 200 return pte; 201 } 202 203 static inline pte_t *pte_alloc(pmd_t *pmd, unsigned long addr) 204 { 205 if (pmd_none(*pmd)) { 206 pte_t *pte = pte_alloc_one(); 207 pmd_val(*pmd) = __pa(pte) | SEGMENT_ENTRY_TT_SEGMENT | 208 SEGMENT_TABLE_LENGTH; 209 } 210 return pte_offset(pmd, addr); 211 } 212 213 static inline void ipte(unsigned long vaddr, pteval_t *p_pte) 214 { 215 unsigned long table_origin = (unsigned long)p_pte & PAGE_MASK; 216 217 asm volatile( 218 " ipte %0,%1\n" 219 : : "a" (table_origin), "a" (vaddr) : "memory"); 220 } 221 222 void configure_dat(int enable); 223 224 #endif /* _ASMS390X_PGTABLE_H_ */ 225