]> rtime.felk.cvut.cz Git - jailhouse.git/blob - hypervisor/paging.c
driver/core: Remove size field from hypervisor header
[jailhouse.git] / hypervisor / paging.c
1 /*
2  * Jailhouse, a Linux-based partitioning hypervisor
3  *
4  * Copyright (c) Siemens AG, 2013
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/printk.h>
15 #include <jailhouse/string.h>
16 #include <jailhouse/control.h>
17 #include <asm/bitops.h>
18
19 #define BITS_PER_PAGE           (PAGE_SIZE * 8)
20
21 #define INVALID_PAGE_NR         (~0UL)
22
23 #define PAGE_SCRUB_ON_FREE      0x1
24
25 extern u8 __page_pool[];
26
27 struct page_pool mem_pool;
28 struct page_pool remap_pool = {
29         .base_address = (void *)REMAP_BASE,
30         .pages = BITS_PER_PAGE * NUM_REMAP_BITMAP_PAGES,
31 };
32
33 struct paging_structures hv_paging_structs;
34
35 unsigned long page_map_get_phys_invalid(pt_entry_t pte, unsigned long virt)
36 {
37         return INVALID_PHYS_ADDR;
38 }
39
40 static unsigned long find_next_free_page(struct page_pool *pool,
41                                          unsigned long start)
42 {
43         unsigned long start_mask =
44                 ~0UL >> (BITS_PER_LONG - (start % BITS_PER_LONG));
45         unsigned long bmp_pos, bmp_val, page_nr;
46
47         if (start >= pool->pages)
48                 return INVALID_PAGE_NR;
49
50         for (bmp_pos = start / BITS_PER_LONG;
51              bmp_pos < pool->pages / BITS_PER_LONG; bmp_pos++) {
52                 bmp_val = pool->used_bitmap[bmp_pos] | start_mask;
53                 start_mask = 0;
54                 if (bmp_val != ~0UL) {
55                         page_nr = ffzl(bmp_val) + bmp_pos * BITS_PER_LONG;
56                         if (page_nr >= pool->pages)
57                                 break;
58                         return page_nr;
59                 }
60         }
61
62         return INVALID_PAGE_NR;
63 }
64
65 void *page_alloc(struct page_pool *pool, unsigned int num)
66 {
67         unsigned long start, last, next;
68         unsigned int allocated;
69
70         start = find_next_free_page(pool, 0);
71         if (start == INVALID_PAGE_NR)
72                 return NULL;
73
74 restart:
75         for (allocated = 1, last = start; allocated < num;
76              allocated++, last = next) {
77                 next = find_next_free_page(pool, last + 1);
78                 if (next == INVALID_PAGE_NR)
79                         return NULL;
80                 if (next != last + 1) {
81                         start = next;
82                         goto restart;
83                 }
84         }
85
86         for (allocated = 0; allocated < num; allocated++)
87                 set_bit(start + allocated, pool->used_bitmap);
88
89         pool->used_pages += num;
90
91         return pool->base_address + start * PAGE_SIZE;
92 }
93
94 void page_free(struct page_pool *pool, void *page, unsigned int num)
95 {
96         unsigned long page_nr;
97
98         if (!page)
99                 return;
100
101         while (num-- > 0) {
102                 if (pool->flags & PAGE_SCRUB_ON_FREE)
103                         memset(page, 0, PAGE_SIZE);
104                 page_nr = (page - pool->base_address) / PAGE_SIZE;
105                 clear_bit(page_nr, pool->used_bitmap);
106                 pool->used_pages--;
107                 page += PAGE_SIZE;
108         }
109 }
110
111 unsigned long page_map_virt2phys(const struct paging_structures *pg_structs,
112                                  unsigned long virt)
113 {
114         const struct paging *paging = pg_structs->root_paging;
115         page_table_t pt = pg_structs->root_table;
116         unsigned long phys;
117         pt_entry_t pte;
118
119         while (1) {
120                 pte = paging->get_entry(pt, virt);
121                 if (!paging->entry_valid(pte))
122                         return INVALID_PHYS_ADDR;
123                 phys = paging->get_phys(pte, virt);
124                 if (phys != INVALID_PHYS_ADDR)
125                         return phys;
126                 pt = page_map_phys2hvirt(paging->get_next_pt(pte));
127                 paging++;
128         }
129 }
130
131 static void flush_pt_entry(pt_entry_t pte, enum page_map_coherent coherent)
132 {
133         if (coherent == PAGE_MAP_COHERENT)
134                 flush_cache(pte, sizeof(*pte));
135 }
136
137 static int split_hugepage(const struct paging *paging, pt_entry_t pte,
138                           unsigned long virt, enum page_map_coherent coherent)
139 {
140         unsigned long phys = paging->get_phys(pte, virt);
141         struct paging_structures sub_structs;
142         unsigned long page_mask, flags;
143
144         if (phys == INVALID_PHYS_ADDR)
145                 return 0;
146
147         page_mask = ~(paging->page_size - 1);
148         phys &= page_mask;
149         virt &= page_mask;
150
151         flags = paging->get_flags(pte);
152
153         sub_structs.root_paging = paging + 1;
154         sub_structs.root_table = page_alloc(&mem_pool, 1);
155         if (!sub_structs.root_table)
156                 return -ENOMEM;
157         paging->set_next_pt(pte, page_map_hvirt2phys(sub_structs.root_table));
158         flush_pt_entry(pte, coherent);
159
160         return page_map_create(&sub_structs, phys, paging->page_size, virt,
161                                flags, coherent);
162 }
163
164 int page_map_create(const struct paging_structures *pg_structs,
165                     unsigned long phys, unsigned long size, unsigned long virt,
166                     unsigned long flags, enum page_map_coherent coherent)
167 {
168         phys &= PAGE_MASK;
169         virt &= PAGE_MASK;
170         size = PAGE_ALIGN(size);
171
172         while (size > 0) {
173                 const struct paging *paging = pg_structs->root_paging;
174                 page_table_t pt = pg_structs->root_table;
175                 pt_entry_t pte;
176                 int err;
177
178                 while (1) {
179                         pte = paging->get_entry(pt, virt);
180                         if (paging->page_size > 0 &&
181                             paging->page_size <= size &&
182                             ((phys | virt) & (paging->page_size - 1)) == 0) {
183                                 /*
184                                  * We might be overwriting a more fine-grained
185                                  * mapping, so release it first. This cannot
186                                  * fail as we are working along hugepage
187                                  * boundaries.
188                                  */
189                                 if (paging->page_size > PAGE_SIZE)
190                                         page_map_destroy(pg_structs, virt,
191                                                          paging->page_size,
192                                                          coherent);
193                                 paging->set_terminal(pte, phys, flags);
194                                 flush_pt_entry(pte, coherent);
195                                 break;
196                         }
197                         if (paging->entry_valid(pte)) {
198                                 err = split_hugepage(paging, pte, virt,
199                                                      coherent);
200                                 if (err)
201                                         return err;
202                                 pt = page_map_phys2hvirt(
203                                                 paging->get_next_pt(pte));
204                         } else {
205                                 pt = page_alloc(&mem_pool, 1);
206                                 if (!pt)
207                                         return -ENOMEM;
208                                 paging->set_next_pt(pte,
209                                                     page_map_hvirt2phys(pt));
210                                 flush_pt_entry(pte, coherent);
211                         }
212                         paging++;
213                 }
214                 arch_tlb_flush_page(virt);
215
216                 phys += paging->page_size;
217                 virt += paging->page_size;
218                 size -= paging->page_size;
219         }
220         return 0;
221 }
222
223 int page_map_destroy(const struct paging_structures *pg_structs,
224                      unsigned long virt, unsigned long size,
225                      enum page_map_coherent coherent)
226 {
227         size = PAGE_ALIGN(size);
228
229         while (size > 0) {
230                 const struct paging *paging = pg_structs->root_paging;
231                 page_table_t pt[MAX_PAGE_DIR_LEVELS];
232                 unsigned long page_size;
233                 pt_entry_t pte;
234                 int n = 0;
235                 int err;
236
237                 /* walk down the page table, saving intermediate tables */
238                 pt[0] = pg_structs->root_table;
239                 while (1) {
240                         pte = paging->get_entry(pt[n], virt);
241                         if (!paging->entry_valid(pte))
242                                 break;
243                         if (paging->get_phys(pte, virt) != INVALID_PHYS_ADDR) {
244                                 if (paging->page_size > size) {
245                                         err = split_hugepage(paging, pte, virt,
246                                                              coherent);
247                                         if (err)
248                                                 return err;
249                                 } else
250                                         break;
251                         }
252                         pt[++n] = page_map_phys2hvirt(
253                                         paging->get_next_pt(pte));
254                         paging++;
255                 }
256                 /* advance by page size of current level paging */
257                 page_size = paging->page_size ? paging->page_size : PAGE_SIZE;
258
259                 /* walk up again, clearing entries, releasing empty tables */
260                 while (1) {
261                         paging->clear_entry(pte);
262                         flush_pt_entry(pte, coherent);
263                         if (n == 0 || !paging->page_table_empty(pt[n]))
264                                 break;
265                         page_free(&mem_pool, pt[n], 1);
266                         paging--;
267                         pte = paging->get_entry(pt[--n], virt);
268                 }
269                 arch_tlb_flush_page(virt);
270
271                 if (page_size > size)
272                         break;
273                 virt += page_size;
274                 size -= page_size;
275         }
276         return 0;
277 }
278
279 void *page_map_get_guest_page(struct per_cpu *cpu_data,
280                               const struct guest_paging_structures *pg_structs,
281                               unsigned long virt, unsigned long flags)
282 {
283         unsigned long page_table_gphys = pg_structs->root_table_gphys;
284         const struct paging *paging = pg_structs->root_paging;
285         unsigned long page_virt, phys, gphys;
286         pt_entry_t pte;
287         int err;
288
289         page_virt = TEMPORARY_MAPPING_BASE +
290                 cpu_data->cpu_id * PAGE_SIZE * NUM_TEMPORARY_PAGES;
291
292         while (1) {
293                 /* map guest page table */
294                 phys = arch_page_map_gphys2phys(cpu_data, page_table_gphys);
295                 if (phys == INVALID_PHYS_ADDR)
296                         return NULL;
297                 err = page_map_create(&hv_paging_structs, phys,
298                                       PAGE_SIZE, page_virt,
299                                       PAGE_READONLY_FLAGS,
300                                       PAGE_MAP_NON_COHERENT);
301                 if (err)
302                         return NULL;
303
304                 /* evaluate page table entry */
305                 pte = paging->get_entry((page_table_t)page_virt, virt);
306                 if (!paging->entry_valid(pte))
307                         return NULL;
308                 gphys = paging->get_phys(pte, virt);
309                 if (gphys != INVALID_PHYS_ADDR)
310                         break;
311                 page_table_gphys = paging->get_next_pt(pte);
312                 paging++;
313         }
314
315         phys = arch_page_map_gphys2phys(cpu_data, gphys);
316         if (phys == INVALID_PHYS_ADDR)
317                 return NULL;
318         /* map guest page */
319         err = page_map_create(&hv_paging_structs, phys, PAGE_SIZE, page_virt,
320                               flags, PAGE_MAP_NON_COHERENT);
321         if (err)
322                 return NULL;
323
324         return (void *)page_virt;
325 }
326
327 int paging_init(void)
328 {
329         unsigned long per_cpu_pages, config_pages, bitmap_pages;
330         unsigned long n;
331         int err;
332
333         per_cpu_pages = hypervisor_header.possible_cpus *
334                 sizeof(struct per_cpu) / PAGE_SIZE;
335
336         system_config = (struct jailhouse_system *)
337                 (__page_pool + per_cpu_pages * PAGE_SIZE);
338         config_pages = (jailhouse_system_config_size(system_config) +
339                         PAGE_SIZE - 1) / PAGE_SIZE;
340
341         mem_pool.pages = (system_config->hypervisor_memory.size -
342                 (__page_pool - (u8 *)&hypervisor_header)) / PAGE_SIZE;
343         bitmap_pages = (mem_pool.pages + BITS_PER_PAGE - 1) / BITS_PER_PAGE;
344
345         if (mem_pool.pages <= per_cpu_pages + config_pages + bitmap_pages)
346                 goto error_nomem;
347
348         mem_pool.base_address = __page_pool;
349         mem_pool.used_bitmap =
350                 (unsigned long *)(__page_pool + per_cpu_pages * PAGE_SIZE +
351                                   config_pages * PAGE_SIZE);
352         mem_pool.used_pages = per_cpu_pages + config_pages + bitmap_pages;
353         for (n = 0; n < mem_pool.used_pages; n++)
354                 set_bit(n, mem_pool.used_bitmap);
355         mem_pool.flags = PAGE_SCRUB_ON_FREE;
356
357         remap_pool.used_bitmap = page_alloc(&mem_pool, NUM_REMAP_BITMAP_PAGES);
358         remap_pool.used_pages =
359                 hypervisor_header.possible_cpus * NUM_TEMPORARY_PAGES;
360         for (n = 0; n < remap_pool.used_pages; n++)
361                 set_bit(n, remap_pool.used_bitmap);
362
363         arch_paging_init();
364
365         hv_paging_structs.root_paging = hv_paging;
366         hv_paging_structs.root_table = page_alloc(&mem_pool, 1);
367         if (!hv_paging_structs.root_table)
368                 goto error_nomem;
369
370         /* Replicate hypervisor mapping of Linux */
371         err = page_map_create(&hv_paging_structs,
372                               page_map_hvirt2phys(&hypervisor_header),
373                               system_config->hypervisor_memory.size,
374                               (unsigned long)&hypervisor_header,
375                               PAGE_DEFAULT_FLAGS, PAGE_MAP_NON_COHERENT);
376         if (err)
377                 goto error_nomem;
378
379         /* Make sure any remappings to the temporary regions can be performed
380          * without allocations of page table pages. */
381         err = page_map_create(&hv_paging_structs, 0,
382                               remap_pool.used_pages * PAGE_SIZE,
383                               TEMPORARY_MAPPING_BASE, PAGE_NONPRESENT_FLAGS,
384                               PAGE_MAP_NON_COHERENT);
385         if (err)
386                 goto error_nomem;
387
388         return 0;
389
390 error_nomem:
391         printk("FATAL: page pool much too small\n");
392         return -ENOMEM;
393 }
394
395 void page_map_dump_stats(const char *when)
396 {
397         printk("Page pool usage %s: mem %d/%d, remap %d/%d\n", when,
398                mem_pool.used_pages, mem_pool.pages,
399                remap_pool.used_pages, remap_pool.pages);
400 }