]> rtime.felk.cvut.cz Git - jailhouse.git/blob - hypervisor/arch/x86/paging.c
x86: Use more BIT_MASK macro for paging tasks
[jailhouse.git] / hypervisor / arch / x86 / paging.c
1 /*
2  * Jailhouse, a Linux-based partitioning hypervisor
3  *
4  * Copyright (c) Siemens AG, 2014-2016
5  *
6  * Authors:
7  *  Jan Kiszka <jan.kiszka@siemens.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2.  See
10  * the COPYING file in the top-level directory.
11  */
12
13 #include <jailhouse/paging.h>
14 #include <jailhouse/string.h>
15 #include <jailhouse/utils.h>
16
17 #define X86_FLAG_HUGEPAGE       0x80
18
19 struct paging hv_paging[MAX_PAGE_TABLE_LEVELS];
20
21 static bool x86_64_entry_valid(pt_entry_t pte, unsigned long flags)
22 {
23         return (*pte & flags) == flags;
24 }
25
26 static unsigned long x86_64_get_flags(pt_entry_t pte)
27 {
28         return *pte & BIT_MASK(6, 0);
29 }
30
31 static void x86_64_set_next_pt(pt_entry_t pte, unsigned long next_pt)
32 {
33         *pte = (next_pt & BIT_MASK(51, 12)) | PAGE_DEFAULT_FLAGS;
34 }
35
36 static void x86_64_clear_entry(pt_entry_t pte)
37 {
38         *pte = 0;
39 }
40
41 static bool x86_64_page_table_empty(page_table_t page_table)
42 {
43         pt_entry_t pte;
44         int n;
45
46         for (n = 0, pte = page_table; n < PAGE_SIZE / sizeof(u64); n++, pte++)
47                 if (x86_64_entry_valid(pte, PAGE_FLAG_PRESENT))
48                         return false;
49         return true;
50 }
51
52 static pt_entry_t x86_64_get_entry_l4(page_table_t page_table,
53                                       unsigned long virt)
54 {
55         return &page_table[(virt >> 39) & 0x1ff];
56 }
57
58 static pt_entry_t x86_64_get_entry_l3(page_table_t page_table,
59                                       unsigned long virt)
60 {
61         return &page_table[(virt >> 30) & 0x1ff];
62 }
63
64 static pt_entry_t x86_64_get_entry_l2(page_table_t page_table,
65                                       unsigned long virt)
66 {
67         return &page_table[(virt >> 21) & 0x1ff];
68 }
69
70 static pt_entry_t x86_64_get_entry_l1(page_table_t page_table,
71                                       unsigned long virt)
72 {
73         return &page_table[(virt >> 12) & 0x1ff];
74 }
75
76 static void x86_64_set_terminal_l3(pt_entry_t pte, unsigned long phys,
77                                    unsigned long flags)
78 {
79         *pte = (phys & BIT_MASK(51, 30)) | X86_FLAG_HUGEPAGE | flags;
80 }
81
82 static void x86_64_set_terminal_l2(pt_entry_t pte, unsigned long phys,
83                                    unsigned long flags)
84 {
85         *pte = (phys & BIT_MASK(51, 21)) | X86_FLAG_HUGEPAGE | flags;
86 }
87
88 static void x86_64_set_terminal_l1(pt_entry_t pte, unsigned long phys,
89                                    unsigned long flags)
90 {
91         *pte = (phys & BIT_MASK(51, 12)) | flags;
92 }
93
94 static unsigned long x86_64_get_phys_l3(pt_entry_t pte, unsigned long virt)
95 {
96         if (!(*pte & X86_FLAG_HUGEPAGE))
97                 return INVALID_PHYS_ADDR;
98         return (*pte & BIT_MASK(51, 30)) | (virt & BIT_MASK(29, 0));
99 }
100
101 static unsigned long x86_64_get_phys_l2(pt_entry_t pte, unsigned long virt)
102 {
103         if (!(*pte & X86_FLAG_HUGEPAGE))
104                 return INVALID_PHYS_ADDR;
105         return (*pte & BIT_MASK(51, 21)) | (virt & BIT_MASK(20, 0));
106 }
107
108 static unsigned long x86_64_get_phys_l1(pt_entry_t pte, unsigned long virt)
109 {
110         return (*pte & BIT_MASK(51, 12)) | (virt & BIT_MASK(11, 0));
111 }
112
113 static unsigned long x86_64_get_next_pt(pt_entry_t pte)
114 {
115         return *pte & BIT_MASK(51, 12);
116 }
117
118 #define X86_64_PAGING_COMMON                                    \
119         .entry_valid            = x86_64_entry_valid,           \
120         .get_flags              = x86_64_get_flags,             \
121         .set_next_pt            = x86_64_set_next_pt,           \
122         .clear_entry            = x86_64_clear_entry,           \
123         .page_table_empty       = x86_64_page_table_empty
124
125 const struct paging x86_64_paging[] = {
126         {
127                 X86_64_PAGING_COMMON,
128                 .get_entry      = x86_64_get_entry_l4,
129                 /* set_terminal not valid */
130                 .get_phys       = paging_get_phys_invalid,
131                 .get_next_pt    = x86_64_get_next_pt,
132         },
133         {
134                 .page_size      = 1024 * 1024 * 1024,
135                 X86_64_PAGING_COMMON,
136                 .get_entry      = x86_64_get_entry_l3,
137                 .set_terminal   = x86_64_set_terminal_l3,
138                 .get_phys       = x86_64_get_phys_l3,
139                 .get_next_pt    = x86_64_get_next_pt,
140         },
141         {
142                 .page_size      = 2 * 1024 * 1024,
143                 X86_64_PAGING_COMMON,
144                 .get_entry      = x86_64_get_entry_l2,
145                 .set_terminal   = x86_64_set_terminal_l2,
146                 .get_phys       = x86_64_get_phys_l2,
147                 .get_next_pt    = x86_64_get_next_pt,
148         },
149         {
150                 .page_size      = PAGE_SIZE,
151                 X86_64_PAGING_COMMON,
152                 .get_entry      = x86_64_get_entry_l1,
153                 .set_terminal   = x86_64_set_terminal_l1,
154                 .get_phys       = x86_64_get_phys_l1,
155                 /* get_next_pt not valid */
156         },
157 };
158
159 void arch_paging_init(void)
160 {
161         memcpy(hv_paging, x86_64_paging, sizeof(x86_64_paging));
162         if (!(cpuid_edx(0x80000001, 0) & X86_FEATURE_GBPAGES))
163                 hv_paging[1].page_size = 0;
164 }
165
166 static bool i386_entry_valid(pt_entry_t pte, unsigned long flags)
167 {
168         return (*(u32 *)pte & flags) == flags;
169 }
170
171 static pt_entry_t i386_get_entry_l2(page_table_t page_table,
172                                     unsigned long virt)
173 {
174         u32 *page_table32 = (u32 *)page_table;
175
176         return (pt_entry_t)&page_table32[(virt >> 22) & 0x3ff];
177 }
178
179 static pt_entry_t i386_get_entry_l1(page_table_t page_table,
180                                     unsigned long virt)
181 {
182         u32 *page_table32 = (u32 *)page_table;
183
184         return (pt_entry_t)&page_table32[(virt >> 12) & 0x3ff];
185 }
186
187 static unsigned long i386_get_phys_l2(pt_entry_t pte, unsigned long virt)
188 {
189         u32 pte32 = *(u32 *)pte;
190
191         if (!(pte32 & X86_FLAG_HUGEPAGE))
192                 return INVALID_PHYS_ADDR;
193         return ((unsigned long)(pte32 & BIT_MASK(16, 13)) << (32 - 13)) |
194                 (pte32 & BIT_MASK(31, 22)) | (virt & BIT_MASK(21, 0));
195 }
196
197 static unsigned long i386_get_phys_l1(pt_entry_t pte, unsigned long virt)
198 {
199         return (*(u32 *)pte & BIT_MASK(31, 12)) | (virt & BIT_MASK(11, 0));
200 }
201
202 static unsigned long i386_get_next_pt(pt_entry_t pte)
203 {
204         return *(u32 *)pte & BIT_MASK(31, 12);
205 }
206
207 /* read-only, no page table construction supported */
208 const struct paging i386_paging[] = {
209         {
210                 .page_size      = 4 * 1024 * 1024,
211                 .entry_valid    = i386_entry_valid,
212                 .get_entry      = i386_get_entry_l2,
213                 .get_phys       = i386_get_phys_l2,
214                 .get_next_pt    = i386_get_next_pt,
215         },
216         {
217                 .page_size      = PAGE_SIZE,
218                 .entry_valid    = i386_entry_valid,
219                 .get_entry      = i386_get_entry_l1,
220                 .get_phys       = i386_get_phys_l1,
221                 /* get_next_pt not valid */
222         },
223 };
224
225 static bool realmode_entry_valid(pt_entry_t pte, unsigned long flags)
226 {
227         return true;
228 }
229
230 static pt_entry_t realmode_get_entry(page_table_t page_table,
231                 unsigned long virt)
232 {
233         return NULL;
234 }
235
236 static unsigned long realmode_get_phys(pt_entry_t pte, unsigned long virt)
237 {
238         return virt;
239 }
240
241 /* naturally read-only */
242 const struct paging realmode_paging[] = {
243         {
244                 .page_size      = PAGE_SIZE,
245                 .entry_valid    = realmode_entry_valid,
246                 .get_entry      = realmode_get_entry,
247                 .get_phys       = realmode_get_phys,
248                 /* get_next_pt not valid */
249         },
250 };