aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>2010-12-13 09:42:30 -0500
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2011-01-11 14:32:14 -0500
commit87f1d40a706bdebdc8f959b9ac291d0d8fdfcc7e (patch)
tree9c05cb059c6eec2d85effd95642ee1a42b000fbe /arch
parenta12b4eb34bb1ea16046c5b61e7a887e252cc1cce (diff)
xen p2m: clear the old pte when adding a page to m2p_override
When adding a page to m2p_override we change the p2m of the page so we need to also clear the old pte of the kernel linear mapping because it doesn't correspond anymore. When we remove the page from m2p_override we restore the original p2m of the page and we also restore the old pte of the kernel linear mapping. Before changing the p2m mappings in m2p_add_override and m2p_remove_override, check that the page passed as argument is valid and return an error if it is not. Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/xen/page.h4
-rw-r--r--arch/x86/xen/p2m.c49
2 files changed, 47 insertions, 6 deletions
diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
index 50f0a0f6bd6..f25bdf238a3 100644
--- a/arch/x86/include/asm/xen/page.h
+++ b/arch/x86/include/asm/xen/page.h
@@ -42,8 +42,8 @@ extern unsigned int machine_to_phys_order;
42extern unsigned long get_phys_to_machine(unsigned long pfn); 42extern unsigned long get_phys_to_machine(unsigned long pfn);
43extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn); 43extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
44 44
45extern void m2p_add_override(unsigned long mfn, struct page *page); 45extern int m2p_add_override(unsigned long mfn, struct page *page);
46extern void m2p_remove_override(struct page *page); 46extern int m2p_remove_override(struct page *page);
47extern struct page *m2p_find_override(unsigned long mfn); 47extern struct page *m2p_find_override(unsigned long mfn);
48extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn); 48extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn);
49 49
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
index b3b19d43b95..40d51225ff0 100644
--- a/arch/x86/xen/p2m.c
+++ b/arch/x86/xen/p2m.c
@@ -29,6 +29,7 @@
29#include <linux/module.h> 29#include <linux/module.h>
30#include <linux/list.h> 30#include <linux/list.h>
31#include <linux/hash.h> 31#include <linux/hash.h>
32#include <linux/sched.h>
32 33
33#include <asm/cache.h> 34#include <asm/cache.h>
34#include <asm/setup.h> 35#include <asm/setup.h>
@@ -404,34 +405,74 @@ static unsigned long mfn_hash(unsigned long mfn)
404} 405}
405 406
406/* Add an MFN override for a particular page */ 407/* Add an MFN override for a particular page */
407void m2p_add_override(unsigned long mfn, struct page *page) 408int m2p_add_override(unsigned long mfn, struct page *page)
408{ 409{
409 unsigned long flags; 410 unsigned long flags;
410 unsigned long pfn = page_to_pfn(page); 411 unsigned long pfn;
412 unsigned long address;
413 unsigned level;
414 pte_t *ptep = NULL;
415
416 pfn = page_to_pfn(page);
417 if (!PageHighMem(page)) {
418 address = (unsigned long)__va(pfn << PAGE_SHIFT);
419 ptep = lookup_address(address, &level);
420
421 if (WARN(ptep == NULL || level != PG_LEVEL_4K,
422 "m2p_add_override: pfn %lx not mapped", pfn))
423 return -EINVAL;
424 }
425
411 page->private = mfn; 426 page->private = mfn;
412 page->index = pfn_to_mfn(pfn); 427 page->index = pfn_to_mfn(pfn);
413 428
414 __set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)); 429 __set_phys_to_machine(pfn, FOREIGN_FRAME(mfn));
430 if (!PageHighMem(page))
431 /* Just zap old mapping for now */
432 pte_clear(&init_mm, address, ptep);
433
415 spin_lock_irqsave(&m2p_override_lock, flags); 434 spin_lock_irqsave(&m2p_override_lock, flags);
416 list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]); 435 list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]);
417 spin_unlock_irqrestore(&m2p_override_lock, flags); 436 spin_unlock_irqrestore(&m2p_override_lock, flags);
437
438 return 0;
418} 439}
419 440
420void m2p_remove_override(struct page *page) 441int m2p_remove_override(struct page *page)
421{ 442{
422 unsigned long flags; 443 unsigned long flags;
423 unsigned long mfn; 444 unsigned long mfn;
424 unsigned long pfn; 445 unsigned long pfn;
446 unsigned long address;
447 unsigned level;
448 pte_t *ptep = NULL;
425 449
426 pfn = page_to_pfn(page); 450 pfn = page_to_pfn(page);
427 mfn = get_phys_to_machine(pfn); 451 mfn = get_phys_to_machine(pfn);
428 if (mfn == INVALID_P2M_ENTRY || !(mfn & FOREIGN_FRAME_BIT)) 452 if (mfn == INVALID_P2M_ENTRY || !(mfn & FOREIGN_FRAME_BIT))
429 return; 453 return -EINVAL;
454
455 if (!PageHighMem(page)) {
456 address = (unsigned long)__va(pfn << PAGE_SHIFT);
457 ptep = lookup_address(address, &level);
458
459 if (WARN(ptep == NULL || level != PG_LEVEL_4K,
460 "m2p_remove_override: pfn %lx not mapped", pfn))
461 return -EINVAL;
462 }
430 463
431 spin_lock_irqsave(&m2p_override_lock, flags); 464 spin_lock_irqsave(&m2p_override_lock, flags);
432 list_del(&page->lru); 465 list_del(&page->lru);
433 spin_unlock_irqrestore(&m2p_override_lock, flags); 466 spin_unlock_irqrestore(&m2p_override_lock, flags);
434 __set_phys_to_machine(pfn, page->index); 467 __set_phys_to_machine(pfn, page->index);
468
469 if (!PageHighMem(page))
470 set_pte_at(&init_mm, address, ptep,
471 pfn_pte(pfn, PAGE_KERNEL));
472 /* No tlb flush necessary because the caller already
473 * left the pte unmapped. */
474
475 return 0;
435} 476}
436 477
437struct page *m2p_find_override(unsigned long mfn) 478struct page *m2p_find_override(unsigned long mfn)