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