diff options
Diffstat (limited to 'arch/x86/kernel/vmi_32.c')
-rw-r--r-- | arch/x86/kernel/vmi_32.c | 135 |
1 files changed, 11 insertions, 124 deletions
diff --git a/arch/x86/kernel/vmi_32.c b/arch/x86/kernel/vmi_32.c index 8b6c393ab9f..23206ba1687 100644 --- a/arch/x86/kernel/vmi_32.c +++ b/arch/x86/kernel/vmi_32.c | |||
@@ -266,109 +266,6 @@ static void vmi_nop(void) | |||
266 | { | 266 | { |
267 | } | 267 | } |
268 | 268 | ||
269 | #ifdef CONFIG_DEBUG_PAGE_TYPE | ||
270 | |||
271 | #ifdef CONFIG_X86_PAE | ||
272 | #define MAX_BOOT_PTS (2048+4+1) | ||
273 | #else | ||
274 | #define MAX_BOOT_PTS (1024+1) | ||
275 | #endif | ||
276 | |||
277 | /* | ||
278 | * During boot, mem_map is not yet available in paging_init, so stash | ||
279 | * all the boot page allocations here. | ||
280 | */ | ||
281 | static struct { | ||
282 | u32 pfn; | ||
283 | int type; | ||
284 | } boot_page_allocations[MAX_BOOT_PTS]; | ||
285 | static int num_boot_page_allocations; | ||
286 | static int boot_allocations_applied; | ||
287 | |||
288 | void vmi_apply_boot_page_allocations(void) | ||
289 | { | ||
290 | int i; | ||
291 | BUG_ON(!mem_map); | ||
292 | for (i = 0; i < num_boot_page_allocations; i++) { | ||
293 | struct page *page = pfn_to_page(boot_page_allocations[i].pfn); | ||
294 | page->type = boot_page_allocations[i].type; | ||
295 | page->type = boot_page_allocations[i].type & | ||
296 | ~(VMI_PAGE_ZEROED | VMI_PAGE_CLONE); | ||
297 | } | ||
298 | boot_allocations_applied = 1; | ||
299 | } | ||
300 | |||
301 | static void record_page_type(u32 pfn, int type) | ||
302 | { | ||
303 | BUG_ON(num_boot_page_allocations >= MAX_BOOT_PTS); | ||
304 | boot_page_allocations[num_boot_page_allocations].pfn = pfn; | ||
305 | boot_page_allocations[num_boot_page_allocations].type = type; | ||
306 | num_boot_page_allocations++; | ||
307 | } | ||
308 | |||
309 | static void check_zeroed_page(u32 pfn, int type, struct page *page) | ||
310 | { | ||
311 | u32 *ptr; | ||
312 | int i; | ||
313 | int limit = PAGE_SIZE / sizeof(int); | ||
314 | |||
315 | if (page_address(page)) | ||
316 | ptr = (u32 *)page_address(page); | ||
317 | else | ||
318 | ptr = (u32 *)__va(pfn << PAGE_SHIFT); | ||
319 | /* | ||
320 | * When cloning the root in non-PAE mode, only the userspace | ||
321 | * pdes need to be zeroed. | ||
322 | */ | ||
323 | if (type & VMI_PAGE_CLONE) | ||
324 | limit = KERNEL_PGD_BOUNDARY; | ||
325 | for (i = 0; i < limit; i++) | ||
326 | BUG_ON(ptr[i]); | ||
327 | } | ||
328 | |||
329 | /* | ||
330 | * We stash the page type into struct page so we can verify the page | ||
331 | * types are used properly. | ||
332 | */ | ||
333 | static void vmi_set_page_type(u32 pfn, int type) | ||
334 | { | ||
335 | /* PAE can have multiple roots per page - don't track */ | ||
336 | if (PTRS_PER_PMD > 1 && (type & VMI_PAGE_PDP)) | ||
337 | return; | ||
338 | |||
339 | if (boot_allocations_applied) { | ||
340 | struct page *page = pfn_to_page(pfn); | ||
341 | if (type != VMI_PAGE_NORMAL) | ||
342 | BUG_ON(page->type); | ||
343 | else | ||
344 | BUG_ON(page->type == VMI_PAGE_NORMAL); | ||
345 | page->type = type & ~(VMI_PAGE_ZEROED | VMI_PAGE_CLONE); | ||
346 | if (type & VMI_PAGE_ZEROED) | ||
347 | check_zeroed_page(pfn, type, page); | ||
348 | } else { | ||
349 | record_page_type(pfn, type); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | static void vmi_check_page_type(u32 pfn, int type) | ||
354 | { | ||
355 | /* PAE can have multiple roots per page - skip checks */ | ||
356 | if (PTRS_PER_PMD > 1 && (type & VMI_PAGE_PDP)) | ||
357 | return; | ||
358 | |||
359 | type &= ~(VMI_PAGE_ZEROED | VMI_PAGE_CLONE); | ||
360 | if (boot_allocations_applied) { | ||
361 | struct page *page = pfn_to_page(pfn); | ||
362 | BUG_ON((page->type ^ type) & VMI_PAGE_PAE); | ||
363 | BUG_ON(type == VMI_PAGE_NORMAL && page->type); | ||
364 | BUG_ON((type & page->type) == 0); | ||
365 | } | ||
366 | } | ||
367 | #else | ||
368 | #define vmi_set_page_type(p,t) do { } while (0) | ||
369 | #define vmi_check_page_type(p,t) do { } while (0) | ||
370 | #endif | ||
371 | |||
372 | #ifdef CONFIG_HIGHPTE | 269 | #ifdef CONFIG_HIGHPTE |
373 | static void *vmi_kmap_atomic_pte(struct page *page, enum km_type type) | 270 | static void *vmi_kmap_atomic_pte(struct page *page, enum km_type type) |
374 | { | 271 | { |
@@ -395,7 +292,6 @@ static void *vmi_kmap_atomic_pte(struct page *page, enum km_type type) | |||
395 | 292 | ||
396 | static void vmi_allocate_pte(struct mm_struct *mm, unsigned long pfn) | 293 | static void vmi_allocate_pte(struct mm_struct *mm, unsigned long pfn) |
397 | { | 294 | { |
398 | vmi_set_page_type(pfn, VMI_PAGE_L1); | ||
399 | vmi_ops.allocate_page(pfn, VMI_PAGE_L1, 0, 0, 0); | 295 | vmi_ops.allocate_page(pfn, VMI_PAGE_L1, 0, 0, 0); |
400 | } | 296 | } |
401 | 297 | ||
@@ -406,27 +302,22 @@ static void vmi_allocate_pmd(struct mm_struct *mm, unsigned long pfn) | |||
406 | * It is called only for swapper_pg_dir, which already has | 302 | * It is called only for swapper_pg_dir, which already has |
407 | * data on it. | 303 | * data on it. |
408 | */ | 304 | */ |
409 | vmi_set_page_type(pfn, VMI_PAGE_L2); | ||
410 | vmi_ops.allocate_page(pfn, VMI_PAGE_L2, 0, 0, 0); | 305 | vmi_ops.allocate_page(pfn, VMI_PAGE_L2, 0, 0, 0); |
411 | } | 306 | } |
412 | 307 | ||
413 | static void vmi_allocate_pmd_clone(unsigned long pfn, unsigned long clonepfn, unsigned long start, unsigned long count) | 308 | static void vmi_allocate_pmd_clone(unsigned long pfn, unsigned long clonepfn, unsigned long start, unsigned long count) |
414 | { | 309 | { |
415 | vmi_set_page_type(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE); | ||
416 | vmi_check_page_type(clonepfn, VMI_PAGE_L2); | ||
417 | vmi_ops.allocate_page(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE, clonepfn, start, count); | 310 | vmi_ops.allocate_page(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE, clonepfn, start, count); |
418 | } | 311 | } |
419 | 312 | ||
420 | static void vmi_release_pte(unsigned long pfn) | 313 | static void vmi_release_pte(unsigned long pfn) |
421 | { | 314 | { |
422 | vmi_ops.release_page(pfn, VMI_PAGE_L1); | 315 | vmi_ops.release_page(pfn, VMI_PAGE_L1); |
423 | vmi_set_page_type(pfn, VMI_PAGE_NORMAL); | ||
424 | } | 316 | } |
425 | 317 | ||
426 | static void vmi_release_pmd(unsigned long pfn) | 318 | static void vmi_release_pmd(unsigned long pfn) |
427 | { | 319 | { |
428 | vmi_ops.release_page(pfn, VMI_PAGE_L2); | 320 | vmi_ops.release_page(pfn, VMI_PAGE_L2); |
429 | vmi_set_page_type(pfn, VMI_PAGE_NORMAL); | ||
430 | } | 321 | } |
431 | 322 | ||
432 | /* | 323 | /* |
@@ -450,26 +341,22 @@ static void vmi_release_pmd(unsigned long pfn) | |||
450 | 341 | ||
451 | static void vmi_update_pte(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | 342 | static void vmi_update_pte(struct mm_struct *mm, unsigned long addr, pte_t *ptep) |
452 | { | 343 | { |
453 | vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); | ||
454 | vmi_ops.update_pte(ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0)); | 344 | vmi_ops.update_pte(ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0)); |
455 | } | 345 | } |
456 | 346 | ||
457 | static void vmi_update_pte_defer(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | 347 | static void vmi_update_pte_defer(struct mm_struct *mm, unsigned long addr, pte_t *ptep) |
458 | { | 348 | { |
459 | vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); | ||
460 | vmi_ops.update_pte(ptep, vmi_flags_addr_defer(mm, addr, VMI_PAGE_PT, 0)); | 349 | vmi_ops.update_pte(ptep, vmi_flags_addr_defer(mm, addr, VMI_PAGE_PT, 0)); |
461 | } | 350 | } |
462 | 351 | ||
463 | static void vmi_set_pte(pte_t *ptep, pte_t pte) | 352 | static void vmi_set_pte(pte_t *ptep, pte_t pte) |
464 | { | 353 | { |
465 | /* XXX because of set_pmd_pte, this can be called on PT or PD layers */ | 354 | /* XXX because of set_pmd_pte, this can be called on PT or PD layers */ |
466 | vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE | VMI_PAGE_PD); | ||
467 | vmi_ops.set_pte(pte, ptep, VMI_PAGE_PT); | 355 | vmi_ops.set_pte(pte, ptep, VMI_PAGE_PT); |
468 | } | 356 | } |
469 | 357 | ||
470 | static void vmi_set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) | 358 | static void vmi_set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) |
471 | { | 359 | { |
472 | vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); | ||
473 | vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0)); | 360 | vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0)); |
474 | } | 361 | } |
475 | 362 | ||
@@ -477,10 +364,8 @@ static void vmi_set_pmd(pmd_t *pmdp, pmd_t pmdval) | |||
477 | { | 364 | { |
478 | #ifdef CONFIG_X86_PAE | 365 | #ifdef CONFIG_X86_PAE |
479 | const pte_t pte = { .pte = pmdval.pmd }; | 366 | const pte_t pte = { .pte = pmdval.pmd }; |
480 | vmi_check_page_type(__pa(pmdp) >> PAGE_SHIFT, VMI_PAGE_PMD); | ||
481 | #else | 367 | #else |
482 | const pte_t pte = { pmdval.pud.pgd.pgd }; | 368 | const pte_t pte = { pmdval.pud.pgd.pgd }; |
483 | vmi_check_page_type(__pa(pmdp) >> PAGE_SHIFT, VMI_PAGE_PGD); | ||
484 | #endif | 369 | #endif |
485 | vmi_ops.set_pte(pte, (pte_t *)pmdp, VMI_PAGE_PD); | 370 | vmi_ops.set_pte(pte, (pte_t *)pmdp, VMI_PAGE_PD); |
486 | } | 371 | } |
@@ -502,7 +387,6 @@ static void vmi_set_pte_atomic(pte_t *ptep, pte_t pteval) | |||
502 | 387 | ||
503 | static void vmi_set_pte_present(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) | 388 | static void vmi_set_pte_present(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) |
504 | { | 389 | { |
505 | vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); | ||
506 | vmi_ops.set_pte(pte, ptep, vmi_flags_addr_defer(mm, addr, VMI_PAGE_PT, 1)); | 390 | vmi_ops.set_pte(pte, ptep, vmi_flags_addr_defer(mm, addr, VMI_PAGE_PT, 1)); |
507 | } | 391 | } |
508 | 392 | ||
@@ -510,21 +394,18 @@ static void vmi_set_pud(pud_t *pudp, pud_t pudval) | |||
510 | { | 394 | { |
511 | /* Um, eww */ | 395 | /* Um, eww */ |
512 | const pte_t pte = { .pte = pudval.pgd.pgd }; | 396 | const pte_t pte = { .pte = pudval.pgd.pgd }; |
513 | vmi_check_page_type(__pa(pudp) >> PAGE_SHIFT, VMI_PAGE_PGD); | ||
514 | vmi_ops.set_pte(pte, (pte_t *)pudp, VMI_PAGE_PDP); | 397 | vmi_ops.set_pte(pte, (pte_t *)pudp, VMI_PAGE_PDP); |
515 | } | 398 | } |
516 | 399 | ||
517 | static void vmi_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | 400 | static void vmi_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) |
518 | { | 401 | { |
519 | const pte_t pte = { .pte = 0 }; | 402 | const pte_t pte = { .pte = 0 }; |
520 | vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); | ||
521 | vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0)); | 403 | vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0)); |
522 | } | 404 | } |
523 | 405 | ||
524 | static void vmi_pmd_clear(pmd_t *pmd) | 406 | static void vmi_pmd_clear(pmd_t *pmd) |
525 | { | 407 | { |
526 | const pte_t pte = { .pte = 0 }; | 408 | const pte_t pte = { .pte = 0 }; |
527 | vmi_check_page_type(__pa(pmd) >> PAGE_SHIFT, VMI_PAGE_PMD); | ||
528 | vmi_ops.set_pte(pte, (pte_t *)pmd, VMI_PAGE_PD); | 409 | vmi_ops.set_pte(pte, (pte_t *)pmd, VMI_PAGE_PD); |
529 | } | 410 | } |
530 | #endif | 411 | #endif |
@@ -960,8 +841,6 @@ static inline int __init activate_vmi(void) | |||
960 | 841 | ||
961 | void __init vmi_init(void) | 842 | void __init vmi_init(void) |
962 | { | 843 | { |
963 | unsigned long flags; | ||
964 | |||
965 | if (!vmi_rom) | 844 | if (!vmi_rom) |
966 | probe_vmi_rom(); | 845 | probe_vmi_rom(); |
967 | else | 846 | else |
@@ -973,13 +852,21 @@ void __init vmi_init(void) | |||
973 | 852 | ||
974 | reserve_top_address(-vmi_rom->virtual_top); | 853 | reserve_top_address(-vmi_rom->virtual_top); |
975 | 854 | ||
976 | local_irq_save(flags); | ||
977 | activate_vmi(); | ||
978 | |||
979 | #ifdef CONFIG_X86_IO_APIC | 855 | #ifdef CONFIG_X86_IO_APIC |
980 | /* This is virtual hardware; timer routing is wired correctly */ | 856 | /* This is virtual hardware; timer routing is wired correctly */ |
981 | no_timer_check = 1; | 857 | no_timer_check = 1; |
982 | #endif | 858 | #endif |
859 | } | ||
860 | |||
861 | void vmi_activate(void) | ||
862 | { | ||
863 | unsigned long flags; | ||
864 | |||
865 | if (!vmi_rom) | ||
866 | return; | ||
867 | |||
868 | local_irq_save(flags); | ||
869 | activate_vmi(); | ||
983 | local_irq_restore(flags & X86_EFLAGS_IF); | 870 | local_irq_restore(flags & X86_EFLAGS_IF); |
984 | } | 871 | } |
985 | 872 | ||