2 * Jailhouse, a Linux-based partitioning hypervisor
4 * Copyright (c) Siemens AG, 2013
7 * Jan Kiszka <jan.kiszka@siemens.com>
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
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>
19 #define BITS_PER_PAGE (PAGE_SIZE * 8)
21 #define PAGE_SCRUB_ON_FREE 0x1
23 extern u8 __start[], __page_pool[];
25 struct page_pool mem_pool;
26 struct page_pool remap_pool = {
27 .base_address = (void *)REMAP_BASE_ADDR,
28 .pages = BITS_PER_PAGE * NUM_REMAP_BITMAP_PAGES,
33 static void *page_alloc_one(struct page_pool *pool)
35 unsigned long word, page_nr;
37 for (word = 0; word < pool->pages / BITS_PER_LONG; word++)
38 if (pool->used_bitmap[word] != ~0UL) {
39 page_nr = ffz(pool->used_bitmap[word]) +
41 if (page_nr >= pool->pages)
43 set_bit(page_nr, pool->used_bitmap);
45 return pool->base_address + page_nr * PAGE_SIZE;
51 void *page_alloc(struct page_pool *pool, unsigned int num)
53 void *start, *last, *next;
54 unsigned int allocated;
56 start = page_alloc_one(pool);
60 for (allocated = 1, last = start; allocated < num;
61 allocated++, last = next) {
62 next = page_alloc_one(pool);
63 if (next != last + PAGE_SIZE) {
64 page_free(pool, start, allocated);
72 void page_free(struct page_pool *pool, void *page, unsigned int num)
74 unsigned long page_nr;
80 if (pool->flags & PAGE_SCRUB_ON_FREE)
81 memset(page, 0, PAGE_SIZE);
82 page_nr = (page - pool->base_address) / PAGE_SIZE;
83 clear_bit(page_nr, pool->used_bitmap);
89 unsigned long page_map_virt2phys(pgd_t *page_table,
90 unsigned long page_table_offset,
98 #if PAGE_DIR_LEVELS == 4
99 pgd = pgd_offset(page_table, virt);
101 return INVALID_PHYS_ADDR;
103 pud = pud4l_offset(pgd, page_table_offset, virt);
104 #elif PAGE_DIR_LEVELS == 3
105 pud = pud3l_offset(pgd, page_table_offset, virt);
107 # error Unsupported paging level
110 return INVALID_PHYS_ADDR;
112 pmd = pmd_offset(pud, page_table_offset, virt);
114 return INVALID_PHYS_ADDR;
116 if (pmd_is_hugepage(pmd))
117 return phys_address_hugepage(pmd, virt);
119 pte = pte_offset(pmd, page_table_offset, virt);
121 return INVALID_PHYS_ADDR;
123 return phys_address(pte, virt);
126 int page_map_create(pgd_t *page_table, unsigned long phys, unsigned long size,
127 unsigned long virt, unsigned long flags,
128 unsigned long table_flags, unsigned int levels)
130 unsigned long offs = hypervisor_header.page_offset;
136 for (size = PAGE_ALIGN(size); size > 0;
137 phys += PAGE_SIZE, virt += PAGE_SIZE, size -= PAGE_SIZE) {
140 pgd = pgd_offset(page_table, virt);
141 if (!pgd_valid(pgd)) {
142 pud = page_alloc(&mem_pool, 1);
145 set_pgd(pgd, page_map_hvirt2phys(pud),
148 pud = pud4l_offset(pgd, offs, virt);
151 pud = pud3l_offset(page_table, virt);
157 if (!pud_valid(pud)) {
158 pmd = page_alloc(&mem_pool, 1);
161 set_pud(pud, page_map_hvirt2phys(pmd), table_flags);
164 pmd = pmd_offset(pud, offs, virt);
165 if (!pmd_valid(pmd)) {
166 pte = page_alloc(&mem_pool, 1);
169 set_pmd(pmd, page_map_hvirt2phys(pte), table_flags);
172 pte = pte_offset(pmd, offs, virt);
173 set_pte(pte, phys, flags);
181 void page_map_destroy(pgd_t *page_table, unsigned long virt,
182 unsigned long size, unsigned int levels)
184 unsigned long offs = hypervisor_header.page_offset;
190 for (size = PAGE_ALIGN(size); size > 0;
191 virt += PAGE_SIZE, size -= PAGE_SIZE) {
194 pgd = pgd_offset(page_table, virt);
198 pud = pud4l_offset(pgd, offs, virt);
201 pgd = 0; /* silence compiler warning */
202 pud = pud3l_offset(page_table, virt);
210 pmd = pmd_offset(pud, offs, virt);
214 pte = pte_offset(pmd, offs, virt);
217 if (!pt_empty(pmd, offs))
219 page_free(&mem_pool, pte_offset(pmd, offs, 0), 1);
222 if (!pmd_empty(pud, offs))
224 page_free(&mem_pool, pmd_offset(pud, offs, 0), 1);
227 if (levels < 4 || !pud_empty(pgd, offs))
229 page_free(&mem_pool, pud4l_offset(pgd, offs, 0), 1);
236 void *page_map_get_foreign_page(unsigned int mapping_region,
237 unsigned long page_table_paddr,
238 unsigned long page_table_offset,
239 unsigned long virt, unsigned long flags)
241 unsigned long page_virt, phys;
242 #if PAGE_DIR_LEVELS == 4
250 page_virt = FOREIGN_MAPPING_BASE +
251 mapping_region * PAGE_SIZE * NUM_FOREIGN_PAGES;
253 phys = page_table_paddr + page_table_offset;
254 err = page_map_create(hv_page_table, phys, PAGE_SIZE, page_virt,
255 PAGE_READONLY_FLAGS, PAGE_DEFAULT_FLAGS,
260 #if PAGE_DIR_LEVELS == 4
261 pgd = pgd_offset((pgd_t *)page_virt, virt);
264 phys = (unsigned long)pud4l_offset(pgd, page_table_offset, 0);
265 err = page_map_create(hv_page_table, phys, PAGE_SIZE, page_virt,
266 PAGE_READONLY_FLAGS, PAGE_DEFAULT_FLAGS,
271 pud = pud4l_offset((pgd_t *)&page_virt, page_table_offset, virt);
272 #elif PAGE_DIR_LEVELS == 3
273 pud = pud3l_offset((pgd_t *)page_virt, virt);
275 # error Unsupported paging level
279 phys = (unsigned long)pmd_offset(pud, page_table_offset, 0);
280 err = page_map_create(hv_page_table, phys, PAGE_SIZE, page_virt,
281 PAGE_READONLY_FLAGS, PAGE_DEFAULT_FLAGS,
286 pmd = pmd_offset((pud_t *)&page_virt, page_table_offset, virt);
289 if (pmd_is_hugepage(pmd))
290 phys = phys_address_hugepage(pmd, virt);
292 phys = (unsigned long)pte_offset(pmd, page_table_offset, 0);
293 err = page_map_create(hv_page_table, phys, PAGE_SIZE,
294 page_virt, PAGE_READONLY_FLAGS,
295 PAGE_DEFAULT_FLAGS, PAGE_DIR_LEVELS);
299 pte = pte_offset((pmd_t *)&page_virt, page_table_offset, virt);
302 phys = phys_address(pte, 0) + page_table_offset;
305 err = page_map_create(hv_page_table, phys, PAGE_SIZE, page_virt,
306 flags, PAGE_DEFAULT_FLAGS, PAGE_DIR_LEVELS);
310 return (void *)page_virt;
313 int paging_init(void)
315 unsigned long per_cpu_pages, config_pages, bitmap_pages;
321 (hypervisor_header.size - (__page_pool - __start)) / PAGE_SIZE;
322 per_cpu_pages = hypervisor_header.possible_cpus *
323 sizeof(struct per_cpu) / PAGE_SIZE;
324 bitmap_pages = (mem_pool.pages + BITS_PER_PAGE - 1) / BITS_PER_PAGE;
326 system_config = (struct jailhouse_system *)
327 (__page_pool + per_cpu_pages * PAGE_SIZE);
328 config_pages = (jailhouse_system_config_size(system_config) +
329 PAGE_SIZE - 1) / PAGE_SIZE;
331 if (mem_pool.pages <= per_cpu_pages + config_pages + bitmap_pages)
334 mem_pool.base_address = __page_pool;
335 mem_pool.used_bitmap =
336 (unsigned long *)(__page_pool + per_cpu_pages * PAGE_SIZE +
337 config_pages * PAGE_SIZE);
338 mem_pool.used_pages = per_cpu_pages + config_pages + bitmap_pages;
339 for (n = 0; n < mem_pool.used_pages; n++)
340 set_bit(n, mem_pool.used_bitmap);
341 mem_pool.flags = PAGE_SCRUB_ON_FREE;
343 remap_pool.used_bitmap = page_alloc(&mem_pool, NUM_REMAP_BITMAP_PAGES);
344 remap_pool.used_pages =
345 hypervisor_header.possible_cpus * NUM_FOREIGN_PAGES;
346 for (n = 0; n < remap_pool.used_pages; n++)
347 set_bit(n, remap_pool.used_bitmap);
349 hv_page_table = page_alloc(&mem_pool, 1);
353 /* Replicate hypervisor mapping of Linux */
354 for (addr = __start; addr < __start + hypervisor_header.size;
356 err = page_map_create(hv_page_table, page_map_hvirt2phys(addr),
357 PAGE_SIZE, (unsigned long)addr,
358 PAGE_DEFAULT_FLAGS, PAGE_DEFAULT_FLAGS,
364 /* Make sure any remappings to the foreign regions can be performed
365 * without allocations of page table pages. */
366 err = page_map_create(hv_page_table, 0,
367 remap_pool.used_pages * PAGE_SIZE,
368 FOREIGN_MAPPING_BASE, PAGE_NONPRESENT_FLAGS,
369 PAGE_DEFAULT_FLAGS, PAGE_DIR_LEVELS);
376 printk("FATAL: page pool much too small\n");
380 void page_map_dump_stats(const char *when)
382 printk("Page pool usage %s: mem %d/%d, remap %d/%d\n", when,
383 mem_pool.used_pages, mem_pool.pages,
384 remap_pool.used_pages, remap_pool.pages);