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