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: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
This commit is contained in:
parent
d6382bf77e
commit
e791ca0fd7
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void alloc_p2m(unsigned long pfn)
|
||||||
|
{
|
||||||
|
unsigned long *p;
|
||||||
|
|
||||||
|
p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL);
|
||||||
|
BUG_ON(p == NULL);
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
BUG_ON(mfn != INVALID_P2M_ENTRY);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
topidx = p2m_top_index(pfn);
|
||||||
|
if (p2m_top[topidx] == p2m_missing) {
|
||||||
|
if (mfn == INVALID_P2M_ENTRY)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = p2m_index(pfn);
|
||||||
|
p2m_top[topidx][idx] = mfn;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
|
void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
|
||||||
{
|
{
|
||||||
unsigned topidx, idx;
|
|
||||||
|
|
||||||
if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
|
if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
|
||||||
BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
|
BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(pfn >= MAX_DOMAIN_PAGES)) {
|
if (unlikely(!__set_phys_to_machine(pfn, mfn))) {
|
||||||
BUG_ON(mfn != INVALID_P2M_ENTRY);
|
alloc_p2m(pfn);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
topidx = p2m_top_index(pfn);
|
if (!__set_phys_to_machine(pfn, mfn))
|
||||||
if (p2m_top[topidx] == p2m_missing) {
|
BUG();
|
||||||
/* no need to allocate a page to store an invalid entry */
|
|
||||||
if (mfn == INVALID_P2M_ENTRY)
|
|
||||||
return;
|
|
||||||
alloc_p2m(&p2m_top[topidx], &p2m_top_mfn[topidx]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
idx = p2m_index(pfn);
|
|
||||||
p2m_top[topidx][idx] = mfn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long arbitrary_virt_to_mfn(void *vaddr)
|
unsigned long arbitrary_virt_to_mfn(void *vaddr)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue