xref: /kvm-unit-tests/lib/s390x/asm/pgtable.h (revision c08c320b20287d54c7699a8494619e450b0397b2)
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