aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/xen/page.h16
-rw-r--r--arch/x86/xen/p2m.c80
2 files changed, 93 insertions, 3 deletions
diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
index 8760cc60a21..50f0a0f6bd6 100644
--- a/arch/x86/include/asm/xen/page.h
+++ b/arch/x86/include/asm/xen/page.h
@@ -42,6 +42,11 @@ 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);
46extern void m2p_remove_override(struct page *page);
47extern struct page *m2p_find_override(unsigned long mfn);
48extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn);
49
45static inline unsigned long pfn_to_mfn(unsigned long pfn) 50static inline unsigned long pfn_to_mfn(unsigned long pfn)
46{ 51{
47 unsigned long mfn; 52 unsigned long mfn;
@@ -72,9 +77,6 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn)
72 if (xen_feature(XENFEAT_auto_translated_physmap)) 77 if (xen_feature(XENFEAT_auto_translated_physmap))
73 return mfn; 78 return mfn;
74 79
75 if (unlikely((mfn >> machine_to_phys_order) != 0))
76 return ~0;
77
78 pfn = 0; 80 pfn = 0;
79 /* 81 /*
80 * The array access can fail (e.g., device space beyond end of RAM). 82 * The array access can fail (e.g., device space beyond end of RAM).
@@ -83,6 +85,14 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn)
83 */ 85 */
84 __get_user(pfn, &machine_to_phys_mapping[mfn]); 86 __get_user(pfn, &machine_to_phys_mapping[mfn]);
85 87
88 /*
89 * If this appears to be a foreign mfn (because the pfn
90 * doesn't map back to the mfn), then check the local override
91 * table to see if there's a better pfn to use.
92 */
93 if (get_phys_to_machine(pfn) != mfn)
94 pfn = m2p_find_override_pfn(mfn, pfn);
95
86 return pfn; 96 return pfn;
87} 97}
88 98
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
index 259ec3bb8b6..8db19d50c46 100644
--- a/arch/x86/xen/p2m.c
+++ b/arch/x86/xen/p2m.c
@@ -27,6 +27,8 @@
27 27
28#include <linux/init.h> 28#include <linux/init.h>
29#include <linux/module.h> 29#include <linux/module.h>
30#include <linux/list.h>
31#include <linux/hash.h>
30 32
31#include <asm/cache.h> 33#include <asm/cache.h>
32#include <asm/setup.h> 34#include <asm/setup.h>
@@ -37,6 +39,8 @@
37 39
38#include "xen-ops.h" 40#include "xen-ops.h"
39 41
42static void __init m2p_override_init(void);
43
40unsigned long xen_max_p2m_pfn __read_mostly; 44unsigned long xen_max_p2m_pfn __read_mostly;
41 45
42#define P2M_PER_PAGE (PAGE_SIZE / sizeof(unsigned long)) 46#define P2M_PER_PAGE (PAGE_SIZE / sizeof(unsigned long))
@@ -234,6 +238,8 @@ void __init xen_build_dynamic_phys_to_machine(void)
234 238
235 p2m_top[topidx][mididx] = &mfn_list[pfn]; 239 p2m_top[topidx][mididx] = &mfn_list[pfn];
236 } 240 }
241
242 m2p_override_init();
237} 243}
238 244
239unsigned long get_phys_to_machine(unsigned long pfn) 245unsigned long get_phys_to_machine(unsigned long pfn)
@@ -374,3 +380,77 @@ bool set_phys_to_machine(unsigned long pfn, unsigned long mfn)
374 380
375 return true; 381 return true;
376} 382}
383
384#define M2P_OVERRIDE_HASH_SHIFT 10
385#define M2P_OVERRIDE_HASH (1 << M2P_OVERRIDE_HASH_SHIFT)
386
387static RESERVE_BRK_ARRAY(struct list_head, m2p_overrides, M2P_OVERRIDE_HASH);
388static DEFINE_SPINLOCK(m2p_override_lock);
389
390static void __init m2p_override_init(void)
391{
392 unsigned i;
393
394 m2p_overrides = extend_brk(sizeof(*m2p_overrides) * M2P_OVERRIDE_HASH,
395 sizeof(unsigned long));
396
397 for (i = 0; i < M2P_OVERRIDE_HASH; i++)
398 INIT_LIST_HEAD(&m2p_overrides[i]);
399}
400
401static unsigned long mfn_hash(unsigned long mfn)
402{
403 return hash_long(mfn, M2P_OVERRIDE_HASH_SHIFT);
404}
405
406/* Add an MFN override for a particular page */
407void m2p_add_override(unsigned long mfn, struct page *page)
408{
409 unsigned long flags;
410 page->private = mfn;
411
412 spin_lock_irqsave(&m2p_override_lock, flags);
413 list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]);
414 spin_unlock_irqrestore(&m2p_override_lock, flags);
415}
416
417void m2p_remove_override(struct page *page)
418{
419 unsigned long flags;
420 spin_lock_irqsave(&m2p_override_lock, flags);
421 list_del(&page->lru);
422 spin_unlock_irqrestore(&m2p_override_lock, flags);
423}
424
425struct page *m2p_find_override(unsigned long mfn)
426{
427 unsigned long flags;
428 struct list_head *bucket = &m2p_overrides[mfn_hash(mfn)];
429 struct page *p, *ret;
430
431 ret = NULL;
432
433 spin_lock_irqsave(&m2p_override_lock, flags);
434
435 list_for_each_entry(p, bucket, lru) {
436 if (p->private == mfn) {
437 ret = p;
438 break;
439 }
440 }
441
442 spin_unlock_irqrestore(&m2p_override_lock, flags);
443
444 return ret;
445}
446
447unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn)
448{
449 struct page *p = m2p_find_override(mfn);
450 unsigned long ret = pfn;
451
452 if (p)
453 ret = page_to_pfn(p);
454
455 return ret;
456}