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