Skip to content

Commit

Permalink
xen: make phys_to_machine structure dynamic
Browse files Browse the repository at this point in the history
We now support the use of memory hotplug, so the physical to machine
page mapping structure must be dynamic.  This is implemented as a
two-level radix tree structure, which allows us to efficiently
incrementally allocate memory for the p2m table as new pages are
added.

Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
Jeremy Fitzhardinge authored and Thomas Gleixner committed May 27, 2008
1 parent 955d6f1 commit d451bb7
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 17 deletions.
2 changes: 1 addition & 1 deletion arch/x86/xen/enlighten.c
Original file line number Diff line number Diff line change
Expand Up @@ -1221,7 +1221,7 @@ asmlinkage void __init xen_start_kernel(void)

/* Get mfn list */
if (!xen_feature(XENFEAT_auto_translated_physmap))
phys_to_machine_mapping = (unsigned long *)xen_start_info->mfn_list;
xen_build_dynamic_phys_to_machine();

pgd = (pgd_t *)xen_start_info->pt_base;

Expand Down
85 changes: 85 additions & 0 deletions arch/x86/xen/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,91 @@
#include "multicalls.h"
#include "mmu.h"

/*
* This should probably be a config option. On 32-bit, it costs 1
* page/gig of memory; on 64-bit its 2 pages/gig. If we want it to be
* completely unbounded we can add another level to the p2m structure.
*/
#define MAX_GUEST_PAGES (16ull * 1024*1024*1024 / PAGE_SIZE)
#define P2M_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(unsigned long))

static unsigned long *p2m_top[MAX_GUEST_PAGES / P2M_ENTRIES_PER_PAGE];

static inline unsigned p2m_top_index(unsigned long pfn)
{
BUG_ON(pfn >= MAX_GUEST_PAGES);
return pfn / P2M_ENTRIES_PER_PAGE;
}

static inline unsigned p2m_index(unsigned long pfn)
{
return pfn % P2M_ENTRIES_PER_PAGE;
}

void __init xen_build_dynamic_phys_to_machine(void)
{
unsigned pfn;
unsigned long *mfn_list = (unsigned long *)xen_start_info->mfn_list;

BUG_ON(xen_start_info->nr_pages >= MAX_GUEST_PAGES);

for(pfn = 0;
pfn < xen_start_info->nr_pages;
pfn += P2M_ENTRIES_PER_PAGE) {
unsigned topidx = p2m_top_index(pfn);

p2m_top[topidx] = &mfn_list[pfn];
}
}

unsigned long get_phys_to_machine(unsigned long pfn)
{
unsigned topidx, idx;

topidx = p2m_top_index(pfn);
if (p2m_top[topidx] == NULL)
return INVALID_P2M_ENTRY;

idx = p2m_index(pfn);
return p2m_top[topidx][idx];
}

static void alloc_p2m(unsigned long **pp)
{
unsigned long *p;
unsigned i;

p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL);
BUG_ON(p == NULL);

for(i = 0; i < P2M_ENTRIES_PER_PAGE; i++)
p[i] = INVALID_P2M_ENTRY;

if (cmpxchg(pp, NULL, p) != NULL)
free_page((unsigned long)p);
}

void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
{
unsigned topidx, idx;

if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
return;
}

topidx = p2m_top_index(pfn);
if (p2m_top[topidx] == NULL) {
/* no need to allocate a page to store an invalid entry */
if (mfn == INVALID_P2M_ENTRY)
return;
alloc_p2m(&p2m_top[topidx]);
}

idx = p2m_index(pfn);
p2m_top[topidx][idx] = mfn;
}

xmaddr_t arbitrary_virt_to_machine(unsigned long address)
{
unsigned int level;
Expand Down
2 changes: 0 additions & 2 deletions arch/x86/xen/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@
extern const char xen_hypervisor_callback[];
extern const char xen_failsafe_callback[];

unsigned long *phys_to_machine_mapping;
EXPORT_SYMBOL(phys_to_machine_mapping);

/**
* machine_specific_memory_setup - Hook for machine specific memory setup.
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/xen/xen-ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ void __init xen_arch_setup(void);
void __init xen_init_IRQ(void);
void xen_enable_sysenter(void);

void __init xen_build_dynamic_phys_to_machine(void);

void xen_setup_timer(int cpu);
void xen_setup_cpu_clockevents(void);
unsigned long xen_cpu_khz(void);
Expand Down
20 changes: 6 additions & 14 deletions include/asm-x86/xen/page.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,23 @@ typedef struct xpaddr {
#define FOREIGN_FRAME_BIT (1UL<<31)
#define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT)

extern unsigned long *phys_to_machine_mapping;
extern unsigned long get_phys_to_machine(unsigned long pfn);
extern void set_phys_to_machine(unsigned long pfn, unsigned long mfn);

static inline unsigned long pfn_to_mfn(unsigned long pfn)
{
if (xen_feature(XENFEAT_auto_translated_physmap))
return pfn;

return phys_to_machine_mapping[(unsigned int)(pfn)] &
~FOREIGN_FRAME_BIT;
return get_phys_to_machine(pfn) & ~FOREIGN_FRAME_BIT;
}

static inline int phys_to_machine_mapping_valid(unsigned long pfn)
{
if (xen_feature(XENFEAT_auto_translated_physmap))
return 1;

return (phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY);
return get_phys_to_machine(pfn) != INVALID_P2M_ENTRY;
}

static inline unsigned long mfn_to_pfn(unsigned long mfn)
Expand Down Expand Up @@ -106,20 +106,12 @@ static inline unsigned long mfn_to_local_pfn(unsigned long mfn)
unsigned long pfn = mfn_to_pfn(mfn);
if ((pfn < max_mapnr)
&& !xen_feature(XENFEAT_auto_translated_physmap)
&& (phys_to_machine_mapping[pfn] != mfn))
&& (get_phys_to_machine(pfn) != mfn))
return max_mapnr; /* force !pfn_valid() */
/* XXX fixme; not true with sparsemem */
return pfn;
}

static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
{
if (xen_feature(XENFEAT_auto_translated_physmap)) {
BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
return;
}
phys_to_machine_mapping[pfn] = mfn;
}

/* VIRT <-> MACHINE conversion */
#define virt_to_machine(v) (phys_to_machine(XPADDR(__pa(v))))
#define virt_to_mfn(v) (pfn_to_mfn(PFN_DOWN(__pa(v))))
Expand Down

0 comments on commit d451bb7

Please sign in to comment.