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