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);
179 void page_map_destroy(pgd_t *page_table, unsigned long virt,
180 unsigned long size, unsigned int levels)
182 unsigned long offs = hypervisor_header.page_offset;
188 for (size = PAGE_ALIGN(size); size > 0;
189 virt += PAGE_SIZE, size -= PAGE_SIZE) {
192 pgd = pgd_offset(page_table, virt);
196 pud = pud4l_offset(pgd, offs, virt);
199 pgd = 0; /* silence compiler warning */
200 pud = pud3l_offset(page_table, virt);
208 pmd = pmd_offset(pud, offs, virt);
212 pte = pte_offset(pmd, offs, virt);
215 if (!pt_empty(pmd, offs))
217 page_free(&mem_pool, pte_offset(pmd, offs, 0), 1);
220 if (!pmd_empty(pud, offs))
222 page_free(&mem_pool, pmd_offset(pud, offs, 0), 1);
225 if (levels < 4 || !pud_empty(pgd, offs))
227 page_free(&mem_pool, pud4l_offset(pgd, offs, 0), 1);
234 void *page_map_get_foreign_page(unsigned int mapping_region,
235 unsigned long page_table_paddr,
236 unsigned long page_table_offset,
237 unsigned long virt, unsigned long flags)
239 unsigned long page_virt, pt_virt, phys;
240 #if PAGE_DIR_LEVELS == 4
248 page_virt = FOREIGN_MAPPING_BASE +
249 mapping_region * PAGE_SIZE * NUM_FOREIGN_PAGES;
251 pt_virt = page_virt + PAGE_SIZE;
252 phys = page_table_paddr + page_table_offset;
253 err = page_map_create(hv_page_table, phys, PAGE_SIZE, pt_virt,
254 PAGE_READONLY_FLAGS, PAGE_DEFAULT_FLAGS,
259 #if PAGE_DIR_LEVELS == 4
260 pgd = pgd_offset((pgd_t *)pt_virt, virt);
263 pt_virt += PAGE_SIZE;
264 phys = (unsigned long)pud4l_offset(pgd, page_table_offset, 0);
265 err = page_map_create(hv_page_table, phys, PAGE_SIZE, pt_virt,
266 PAGE_READONLY_FLAGS, PAGE_DEFAULT_FLAGS,
271 pud = pud4l_offset((pgd_t *)&pt_virt, page_table_offset, virt);
272 #elif PAGE_DIR_LEVELS == 3
273 pud = pud3l_offset((pgd_t *)pt_virt, virt);
275 # error Unsupported paging level
279 pt_virt += PAGE_SIZE;
280 phys = (unsigned long)pmd_offset(pud, page_table_offset, 0);
281 err = page_map_create(hv_page_table, phys, PAGE_SIZE, pt_virt,
282 PAGE_READONLY_FLAGS, PAGE_DEFAULT_FLAGS,
287 pmd = pmd_offset((pud_t *)&pt_virt, page_table_offset, virt);
290 if (pmd_is_hugepage(pmd))
291 phys = phys_address_hugepage(pmd, virt);
293 pt_virt += PAGE_SIZE;
294 phys = (unsigned long)pte_offset(pmd, page_table_offset, 0);
295 err = page_map_create(hv_page_table, phys, PAGE_SIZE, pt_virt,
297 PAGE_DEFAULT_FLAGS, PAGE_DIR_LEVELS);
301 pte = pte_offset((pmd_t *)&pt_virt, page_table_offset, virt);
304 phys = phys_address(pte, 0) + page_table_offset;
307 err = page_map_create(hv_page_table, phys, PAGE_SIZE, page_virt,
308 flags, PAGE_DEFAULT_FLAGS, PAGE_DIR_LEVELS);
312 return (void *)page_virt;
315 page_map_release_foreign_page(mapping_region);
319 void page_map_release_foreign_page(unsigned int mapping_region)
321 page_map_destroy(hv_page_table,
322 FOREIGN_MAPPING_BASE +
323 mapping_region * PAGE_SIZE * NUM_FOREIGN_PAGES,
324 NUM_FOREIGN_PAGES * PAGE_SIZE, PAGE_DIR_LEVELS);
327 int paging_init(void)
329 unsigned long per_cpu_pages, config_pages, bitmap_pages;
335 (hypervisor_header.size - (__page_pool - __start)) / PAGE_SIZE;
336 per_cpu_pages = hypervisor_header.possible_cpus *
337 sizeof(struct per_cpu) / PAGE_SIZE;
338 bitmap_pages = (mem_pool.pages + BITS_PER_PAGE - 1) / BITS_PER_PAGE;
340 system_config = (struct jailhouse_system *)
341 (__page_pool + per_cpu_pages * PAGE_SIZE);
342 config_pages = (jailhouse_system_config_size(system_config) +
343 PAGE_SIZE - 1) / PAGE_SIZE;
345 if (mem_pool.pages <= per_cpu_pages + config_pages + bitmap_pages)
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;
357 remap_pool.used_bitmap = page_alloc(&mem_pool, NUM_REMAP_BITMAP_PAGES);
358 remap_pool.used_pages =
359 hypervisor_header.possible_cpus * NUM_FOREIGN_PAGES;
360 for (n = 0; n < remap_pool.used_pages; n++)
361 set_bit(n, remap_pool.used_bitmap);
363 hv_page_table = page_alloc(&mem_pool, 1);
367 /* Replicate hypervisor mapping of Linux */
368 for (addr = __start; addr < __start + hypervisor_header.size;
370 err = page_map_create(hv_page_table, page_map_hvirt2phys(addr),
371 PAGE_SIZE, (unsigned long)addr,
372 PAGE_DEFAULT_FLAGS, PAGE_DEFAULT_FLAGS,
381 printk("FATAL: page pool much too small\n");
385 void page_map_dump_stats(const char *when)
387 printk("Page pool usage %s: mem %d/%d, remap %d/%d\n", when,
388 mem_pool.used_pages, mem_pool.pages,
389 remap_pool.used_pages, remap_pool.pages);