1*6c9f99dfSJanosch 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 63c08c320bSDavid Hildenbrand #define SEGMENT_ENTRY_SFAA 0xfffffffffff80000UL 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 103c08c320bSDavid Hildenbrand #define pgd_addr(entry) __va(pgd_val(entry) & REGION_ENTRY_ORIGIN) 104c08c320bSDavid Hildenbrand #define p4d_addr(entry) __va(p4d_val(entry) & REGION_ENTRY_ORIGIN) 105c08c320bSDavid Hildenbrand #define pud_addr(entry) __va(pud_val(entry) & REGION_ENTRY_ORIGIN) 106c08c320bSDavid Hildenbrand #define pmd_addr(entry) __va(pmd_val(entry) & SEGMENT_ENTRY_ORIGIN) 107c08c320bSDavid Hildenbrand #define pte_addr(entry) __va(pte_val(entry) & PAGE_MASK) 108c08c320bSDavid Hildenbrand 109c08c320bSDavid Hildenbrand #define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) 110c08c320bSDavid Hildenbrand #define p4d_index(addr) (((addr) >> P4D_SHIFT) & (PTRS_PER_P4D - 1)) 111c08c320bSDavid Hildenbrand #define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)) 112c08c320bSDavid Hildenbrand #define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) 113c08c320bSDavid Hildenbrand #define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) 114c08c320bSDavid Hildenbrand 115c08c320bSDavid Hildenbrand #define pgd_offset(table, addr) ((pgd_t *)(table) + pgd_index(addr)) 116c08c320bSDavid Hildenbrand #define p4d_offset(pgd, addr) ((p4d_t *)pgd_addr(*(pgd)) + p4d_index(addr)) 117c08c320bSDavid Hildenbrand #define pud_offset(p4d, addr) ((pud_t *)p4d_addr(*(p4d)) + pud_index(addr)) 118c08c320bSDavid Hildenbrand #define pmd_offset(pud, addr) ((pmd_t *)pud_addr(*(pud)) + pmd_index(addr)) 119c08c320bSDavid Hildenbrand #define pte_offset(pmd, addr) ((pte_t *)pmd_addr(*(pmd)) + pte_index(addr)) 120c08c320bSDavid Hildenbrand 121c08c320bSDavid Hildenbrand static inline pgd_t *pgd_alloc_one(void) 122c08c320bSDavid Hildenbrand { 123c08c320bSDavid Hildenbrand pgd_t *pgd = alloc_pages(REGION_TABLE_ORDER); 124c08c320bSDavid Hildenbrand int i; 125c08c320bSDavid Hildenbrand 126c08c320bSDavid Hildenbrand for (i = 0; i < REGION_TABLE_ENTRIES; i++) 127c08c320bSDavid Hildenbrand pgd_val(pgd[i]) = REGION_ENTRY_TT_REGION1 | REGION_ENTRY_I; 128c08c320bSDavid Hildenbrand return pgd; 129c08c320bSDavid Hildenbrand } 130c08c320bSDavid Hildenbrand 131c08c320bSDavid Hildenbrand static inline p4d_t *p4d_alloc_one(void) 132c08c320bSDavid Hildenbrand { 133c08c320bSDavid Hildenbrand p4d_t *p4d = alloc_pages(REGION_TABLE_ORDER); 134c08c320bSDavid Hildenbrand int i; 135c08c320bSDavid Hildenbrand 136c08c320bSDavid Hildenbrand for (i = 0; i < REGION_TABLE_ENTRIES; i++) 137c08c320bSDavid Hildenbrand p4d_val(p4d[i]) = REGION_ENTRY_TT_REGION2 | REGION_ENTRY_I; 138c08c320bSDavid Hildenbrand return p4d; 139c08c320bSDavid Hildenbrand } 140c08c320bSDavid Hildenbrand 141c08c320bSDavid Hildenbrand static inline p4d_t *p4d_alloc(pgd_t *pgd, unsigned long addr) 142c08c320bSDavid Hildenbrand { 143c08c320bSDavid Hildenbrand if (pgd_none(*pgd)) { 144c08c320bSDavid Hildenbrand p4d_t *p4d = p4d_alloc_one(); 145c08c320bSDavid Hildenbrand pgd_val(*pgd) = __pa(p4d) | REGION_ENTRY_TT_REGION1 | 146c08c320bSDavid Hildenbrand REGION_TABLE_LENGTH; 147c08c320bSDavid Hildenbrand } 148c08c320bSDavid Hildenbrand return p4d_offset(pgd, addr); 149c08c320bSDavid Hildenbrand } 150c08c320bSDavid Hildenbrand 151c08c320bSDavid Hildenbrand static inline pud_t *pud_alloc_one(void) 152c08c320bSDavid Hildenbrand { 153c08c320bSDavid Hildenbrand pud_t *pud = alloc_pages(REGION_TABLE_ORDER); 154c08c320bSDavid Hildenbrand int i; 155c08c320bSDavid Hildenbrand 156c08c320bSDavid Hildenbrand for (i = 0; i < REGION_TABLE_ENTRIES; i++) 157c08c320bSDavid Hildenbrand pud_val(pud[i]) = REGION_ENTRY_TT_REGION3 | REGION_ENTRY_I; 158c08c320bSDavid Hildenbrand return pud; 159c08c320bSDavid Hildenbrand } 160c08c320bSDavid Hildenbrand 161c08c320bSDavid Hildenbrand static inline pud_t *pud_alloc(p4d_t *p4d, unsigned long addr) 162c08c320bSDavid Hildenbrand { 163c08c320bSDavid Hildenbrand if (p4d_none(*p4d)) { 164c08c320bSDavid Hildenbrand pud_t *pud = pud_alloc_one(); 165c08c320bSDavid Hildenbrand p4d_val(*p4d) = __pa(pud) | REGION_ENTRY_TT_REGION2 | 166c08c320bSDavid Hildenbrand REGION_TABLE_LENGTH; 167c08c320bSDavid Hildenbrand } 168c08c320bSDavid Hildenbrand return pud_offset(p4d, addr); 169c08c320bSDavid Hildenbrand } 170c08c320bSDavid Hildenbrand 171c08c320bSDavid Hildenbrand static inline pmd_t *pmd_alloc_one(void) 172c08c320bSDavid Hildenbrand { 173c08c320bSDavid Hildenbrand pmd_t *pmd = alloc_pages(SEGMENT_TABLE_ORDER); 174c08c320bSDavid Hildenbrand int i; 175c08c320bSDavid Hildenbrand 176c08c320bSDavid Hildenbrand for (i = 0; i < SEGMENT_TABLE_ENTRIES; i++) 177c08c320bSDavid Hildenbrand pmd_val(pmd[i]) = SEGMENT_ENTRY_TT_SEGMENT | SEGMENT_ENTRY_I; 178c08c320bSDavid Hildenbrand return pmd; 179c08c320bSDavid Hildenbrand } 180c08c320bSDavid Hildenbrand 181c08c320bSDavid Hildenbrand static inline pmd_t *pmd_alloc(pud_t *pud, unsigned long addr) 182c08c320bSDavid Hildenbrand { 183c08c320bSDavid Hildenbrand if (pud_none(*pud)) { 184c08c320bSDavid Hildenbrand pmd_t *pmd = pmd_alloc_one(); 185c08c320bSDavid Hildenbrand pud_val(*pud) = __pa(pmd) | REGION_ENTRY_TT_REGION3 | 186c08c320bSDavid Hildenbrand REGION_TABLE_LENGTH; 187c08c320bSDavid Hildenbrand } 188c08c320bSDavid Hildenbrand return pmd_offset(pud, addr); 189c08c320bSDavid Hildenbrand } 190c08c320bSDavid Hildenbrand 191c08c320bSDavid Hildenbrand static inline pte_t *pte_alloc_one(void) 192c08c320bSDavid Hildenbrand { 193c08c320bSDavid Hildenbrand pte_t *pte = alloc_pages(PAGE_TABLE_ORDER); 194c08c320bSDavid Hildenbrand int i; 195c08c320bSDavid Hildenbrand 196c08c320bSDavid Hildenbrand for (i = 0; i < PAGE_TABLE_ENTRIES; i++) 197c08c320bSDavid Hildenbrand pte_val(pte[i]) = PAGE_ENTRY_I; 198c08c320bSDavid Hildenbrand return pte; 199c08c320bSDavid Hildenbrand } 200c08c320bSDavid Hildenbrand 201c08c320bSDavid Hildenbrand static inline pte_t *pte_alloc(pmd_t *pmd, unsigned long addr) 202c08c320bSDavid Hildenbrand { 203c08c320bSDavid Hildenbrand if (pmd_none(*pmd)) { 204c08c320bSDavid Hildenbrand pte_t *pte = pte_alloc_one(); 205c08c320bSDavid Hildenbrand pmd_val(*pmd) = __pa(pte) | SEGMENT_ENTRY_TT_SEGMENT | 206c08c320bSDavid Hildenbrand SEGMENT_TABLE_LENGTH; 207c08c320bSDavid Hildenbrand } 208c08c320bSDavid Hildenbrand return pte_offset(pmd, addr); 209c08c320bSDavid Hildenbrand } 210c08c320bSDavid Hildenbrand 211c08c320bSDavid Hildenbrand static inline void ipte(unsigned long vaddr, pteval_t *p_pte) 212c08c320bSDavid Hildenbrand { 213c08c320bSDavid Hildenbrand unsigned long table_origin = (unsigned long)p_pte & PAGE_MASK; 214c08c320bSDavid Hildenbrand 215c08c320bSDavid Hildenbrand asm volatile( 216c08c320bSDavid Hildenbrand " ipte %0,%1\n" 217c08c320bSDavid Hildenbrand : : "a" (table_origin), "a" (vaddr) : "memory"); 218c08c320bSDavid Hildenbrand } 219c08c320bSDavid Hildenbrand 220c08c320bSDavid Hildenbrand void configure_dat(int enable); 221c08c320bSDavid Hildenbrand 222c08c320bSDavid Hildenbrand #endif /* _ASMS390X_PGTABLE_H_ */ 223