Commit e791ca0f authored by Jeremy Fitzhardinge's avatar Jeremy Fitzhardinge

xen: separate p2m allocation from setting

When doing very early p2m setting, we need to separate setting
from allocation, so split things up accordingly.
Signed-off-by: default avatarJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
parent d6382bf7
...@@ -233,47 +233,74 @@ unsigned long get_phys_to_machine(unsigned long pfn) ...@@ -233,47 +233,74 @@ unsigned long get_phys_to_machine(unsigned long pfn)
} }
EXPORT_SYMBOL_GPL(get_phys_to_machine); EXPORT_SYMBOL_GPL(get_phys_to_machine);
static void alloc_p2m(unsigned long **pp, unsigned long *mfnp) /* install a new p2m_top page */
bool install_p2mtop_page(unsigned long pfn, unsigned long *p)
{ {
unsigned long *p; unsigned topidx = p2m_top_index(pfn);
unsigned long **pfnp, *mfnp;
unsigned i; unsigned i;
p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL); pfnp = &p2m_top[topidx];
BUG_ON(p == NULL); mfnp = &p2m_top_mfn[topidx];
for (i = 0; i < P2M_ENTRIES_PER_PAGE; i++) for (i = 0; i < P2M_ENTRIES_PER_PAGE; i++)
p[i] = INVALID_P2M_ENTRY; p[i] = INVALID_P2M_ENTRY;
if (cmpxchg(pp, p2m_missing, p) != p2m_missing) if (cmpxchg(pfnp, p2m_missing, p) == p2m_missing) {
free_page((unsigned long)p);
else
*mfnp = virt_to_mfn(p); *mfnp = virt_to_mfn(p);
return true;
}
return false;
} }
void set_phys_to_machine(unsigned long pfn, unsigned long mfn) static void alloc_p2m(unsigned long pfn)
{ {
unsigned topidx, idx; unsigned long *p;
if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) { p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL);
BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY); BUG_ON(p == NULL);
return;
} if (!install_p2mtop_page(pfn, p))
free_page((unsigned long)p);
}
/* Try to install p2m mapping; fail if intermediate bits missing */
bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
{
unsigned topidx, idx;
if (unlikely(pfn >= MAX_DOMAIN_PAGES)) { if (unlikely(pfn >= MAX_DOMAIN_PAGES)) {
BUG_ON(mfn != INVALID_P2M_ENTRY); BUG_ON(mfn != INVALID_P2M_ENTRY);
return; return true;
} }
topidx = p2m_top_index(pfn); topidx = p2m_top_index(pfn);
if (p2m_top[topidx] == p2m_missing) { if (p2m_top[topidx] == p2m_missing) {
/* no need to allocate a page to store an invalid entry */
if (mfn == INVALID_P2M_ENTRY) if (mfn == INVALID_P2M_ENTRY)
return; return true;
alloc_p2m(&p2m_top[topidx], &p2m_top_mfn[topidx]); return false;
} }
idx = p2m_index(pfn); idx = p2m_index(pfn);
p2m_top[topidx][idx] = mfn; p2m_top[topidx][idx] = mfn;
return true;
}
void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
{
if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
return;
}
if (unlikely(!__set_phys_to_machine(pfn, mfn))) {
alloc_p2m(pfn);
if (!__set_phys_to_machine(pfn, mfn))
BUG();
}
} }
unsigned long arbitrary_virt_to_mfn(void *vaddr) unsigned long arbitrary_virt_to_mfn(void *vaddr)
......
...@@ -11,6 +11,9 @@ enum pt_level { ...@@ -11,6 +11,9 @@ enum pt_level {
}; };
bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
bool install_p2mtop_page(unsigned long pfn, unsigned long *p);
void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags); void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment