#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/memblock.h>
+ +#include <linux/seq_file.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
if (val & _PAGE_PRESENT) {
unsigned long pfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT;
pteval_t flags = val & PTE_FLAGS_MASK;
- - unsigned long mfn = pfn_to_mfn(pfn);
+ + unsigned long mfn;
+ + if (!xen_feature(XENFEAT_auto_translated_physmap))
+ + mfn = get_phys_to_machine(pfn);
+ + else
+ + mfn = pfn;
/*
* If there's no mfn for the pfn, then just create an
* empty non-present pte. Unfortunately this loses
if (unlikely(mfn == INVALID_P2M_ENTRY)) {
mfn = 0;
flags = 0;
+ + } else {
+ + /*
+ + * Paramount to do this test _after_ the
+ + * INVALID_P2M_ENTRY as INVALID_P2M_ENTRY &
+ + * IDENTITY_FRAME_BIT resolves to true.
+ + */
+ + mfn &= ~FOREIGN_FRAME_BIT;
+ + if (mfn & IDENTITY_FRAME_BIT) {
+ + mfn &= ~IDENTITY_FRAME_BIT;
+ + flags |= _PAGE_IOMAP;
+ + }
}
- -
val = ((pteval_t)mfn << PAGE_SHIFT) | flags;
}
}
PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte);
+ +#ifdef CONFIG_XEN_DEBUG
+ +pte_t xen_make_pte_debug(pteval_t pte)
+ +{
+ + phys_addr_t addr = (pte & PTE_PFN_MASK);
+ + phys_addr_t other_addr;
+ + bool io_page = false;
+ + pte_t _pte;
+ +
+ + if (pte & _PAGE_IOMAP)
+ + io_page = true;
+ +
+ + _pte = xen_make_pte(pte);
+ +
+ + if (!addr)
+ + return _pte;
+ +
+ + if (io_page &&
+ + (xen_initial_domain() || addr >= ISA_END_ADDRESS)) {
+ + other_addr = pfn_to_mfn(addr >> PAGE_SHIFT) << PAGE_SHIFT;
+ + WARN(addr != other_addr,
+ + "0x%lx is using VM_IO, but it is 0x%lx!\n",
+ + (unsigned long)addr, (unsigned long)other_addr);
+ + } else {
+ + pteval_t iomap_set = (_pte.pte & PTE_FLAGS_MASK) & _PAGE_IOMAP;
+ + other_addr = (_pte.pte & PTE_PFN_MASK);
+ + WARN((addr == other_addr) && (!io_page) && (!iomap_set),
+ + "0x%lx is missing VM_IO (and wasn't fixed)!\n",
+ + (unsigned long)addr);
+ + }
+ +
+ + return _pte;
+ +}
+ +PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte_debug);
+ +#endif
+ +
pgd_t xen_make_pgd(pgdval_t pgd)
{
pgd = pte_pfn_to_mfn(pgd);
*/
void xen_mm_pin_all(void)
{
-- unsigned long flags;
struct page *page;
-- spin_lock_irqsave(&pgd_lock, flags);
++ spin_lock(&pgd_lock);
list_for_each_entry(page, &pgd_list, lru) {
if (!PagePinned(page)) {
}
}
-- spin_unlock_irqrestore(&pgd_lock, flags);
++ spin_unlock(&pgd_lock);
}
/*
*/
void xen_mm_unpin_all(void)
{
-- unsigned long flags;
struct page *page;
-- spin_lock_irqsave(&pgd_lock, flags);
++ spin_lock(&pgd_lock);
list_for_each_entry(page, &pgd_list, lru) {
if (PageSavePinned(page)) {
}
}
-- spin_unlock_irqrestore(&pgd_lock, flags);
++ spin_unlock(&pgd_lock);
}
void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
static __init void xen_post_allocator_init(void)
{
+ +#ifdef CONFIG_XEN_DEBUG
+ + pv_mmu_ops.make_pte = PV_CALLEE_SAVE(xen_make_pte_debug);
+ +#endif
pv_mmu_ops.set_pte = xen_set_pte;
pv_mmu_ops.set_pmd = xen_set_pmd;
pv_mmu_ops.set_pud = xen_set_pud;
in_frames[i] = virt_to_mfn(vaddr);
MULTI_update_va_mapping(mcs.mc, vaddr, VOID_PTE, 0);
- - set_phys_to_machine(virt_to_pfn(vaddr), INVALID_P2M_ENTRY);
+ + __set_phys_to_machine(virt_to_pfn(vaddr), INVALID_P2M_ENTRY);
if (out_frames)
out_frames[i] = virt_to_pfn(vaddr);
#ifdef CONFIG_XEN_DEBUG_FS
+ +static int p2m_dump_open(struct inode *inode, struct file *filp)
+ +{
+ + return single_open(filp, p2m_dump_show, NULL);
+ +}
+ +
+ +static const struct file_operations p2m_dump_fops = {
+ + .open = p2m_dump_open,
+ + .read = seq_read,
+ + .llseek = seq_lseek,
+ + .release = single_release,
+ +};
+ +
static struct dentry *d_mmu_debug;
static int __init xen_mmu_debugfs(void)
debugfs_create_u32("prot_commit_batched", 0444, d_mmu_debug,
&mmu_stats.prot_commit_batched);
+ + debugfs_create_file("p2m", 0600, d_mmu_debug, NULL, &p2m_dump_fops);
return 0;
}
fs_initcall(xen_mmu_debugfs);
* P2M_PER_PAGE depends on the architecture, as a mfn is always
* unsigned long (8 bytes on 64-bit, 4 bytes on 32), leading to
* 512 and 1024 entries respectively.
+ + *
+ + * In short, these structures contain the Machine Frame Number (MFN) of the PFN.
+ + *
+ + * However not all entries are filled with MFNs. Specifically for all other
+ + * leaf entries, or for the top root, or middle one, for which there is a void
+ + * entry, we assume it is "missing". So (for example)
+ + * pfn_to_mfn(0x90909090)=INVALID_P2M_ENTRY.
+ + *
+ + * We also have the possibility of setting 1-1 mappings on certain regions, so
+ + * that:
+ + * pfn_to_mfn(0xc0000)=0xc0000
+ + *
+ + * The benefit of this is, that we can assume for non-RAM regions (think
+ + * PCI BARs, or ACPI spaces), we can create mappings easily b/c we
+ + * get the PFN value to match the MFN.
+ + *
+ + * For this to work efficiently we have one new page p2m_identity and
+ + * allocate (via reserved_brk) any other pages we need to cover the sides
+ + * (1GB or 4MB boundary violations). All entries in p2m_identity are set to
+ + * INVALID_P2M_ENTRY type (Xen toolstack only recognizes that and MFNs,
+ + * no other fancy value).
+ + *
+ + * On lookup we spot that the entry points to p2m_identity and return the
+ + * identity value instead of dereferencing and returning INVALID_P2M_ENTRY.
+ + * If the entry points to an allocated page, we just proceed as before and
+ + * return the PFN. If the PFN has IDENTITY_FRAME_BIT set we unmask that in
+ + * appropriate functions (pfn_to_mfn).
+ + *
+ + * The reason for having the IDENTITY_FRAME_BIT instead of just returning the
+ + * PFN is that we could find ourselves where pfn_to_mfn(pfn)==pfn for a
+ + * non-identity pfn. To protect ourselves against we elect to set (and get) the
+ + * IDENTITY_FRAME_BIT on all identity mapped PFNs.
+ + *
+ + * This simplistic diagram is used to explain the more subtle piece of code.
+ + * There is also a digram of the P2M at the end that can help.
+ + * Imagine your E820 looking as so:
+ + *
+ + * 1GB 2GB
+ + * /-------------------+---------\/----\ /----------\ /---+-----\
+ + * | System RAM | Sys RAM ||ACPI| | reserved | | Sys RAM |
+ + * \-------------------+---------/\----/ \----------/ \---+-----/
+ + * ^- 1029MB ^- 2001MB
+ + *
+ + * [1029MB = 263424 (0x40500), 2001MB = 512256 (0x7D100),
+ + * 2048MB = 524288 (0x80000)]
+ + *
+ + * And dom0_mem=max:3GB,1GB is passed in to the guest, meaning memory past 1GB
+ + * is actually not present (would have to kick the balloon driver to put it in).
+ + *
+ + * When we are told to set the PFNs for identity mapping (see patch: "xen/setup:
+ + * Set identity mapping for non-RAM E820 and E820 gaps.") we pass in the start
+ + * of the PFN and the end PFN (263424 and 512256 respectively). The first step
+ + * is to reserve_brk a top leaf page if the p2m[1] is missing. The top leaf page
+ + * covers 512^2 of page estate (1GB) and in case the start or end PFN is not
+ + * aligned on 512^2*PAGE_SIZE (1GB) we loop on aligned 1GB PFNs from start pfn
+ + * to end pfn. We reserve_brk top leaf pages if they are missing (means they
+ + * point to p2m_mid_missing).
+ + *
+ + * With the E820 example above, 263424 is not 1GB aligned so we allocate a
+ + * reserve_brk page which will cover the PFNs estate from 0x40000 to 0x80000.
+ + * Each entry in the allocate page is "missing" (points to p2m_missing).
+ + *
+ + * Next stage is to determine if we need to do a more granular boundary check
+ + * on the 4MB (or 2MB depending on architecture) off the start and end pfn's.
+ + * We check if the start pfn and end pfn violate that boundary check, and if
+ + * so reserve_brk a middle (p2m[x][y]) leaf page. This way we have a much finer
+ + * granularity of setting which PFNs are missing and which ones are identity.
+ + * In our example 263424 and 512256 both fail the check so we reserve_brk two
+ + * pages. Populate them with INVALID_P2M_ENTRY (so they both have "missing"
+ + * values) and assign them to p2m[1][2] and p2m[1][488] respectively.
+ + *
+ + * At this point we would at minimum reserve_brk one page, but could be up to
+ + * three. Each call to set_phys_range_identity has at maximum a three page
+ + * cost. If we were to query the P2M at this stage, all those entries from
+ + * start PFN through end PFN (so 1029MB -> 2001MB) would return
+ + * INVALID_P2M_ENTRY ("missing").
+ + *
+ + * The next step is to walk from the start pfn to the end pfn setting
+ + * the IDENTITY_FRAME_BIT on each PFN. This is done in set_phys_range_identity.
+ + * If we find that the middle leaf is pointing to p2m_missing we can swap it
+ + * over to p2m_identity - this way covering 4MB (or 2MB) PFN space. At this
+ + * point we do not need to worry about boundary aligment (so no need to
+ + * reserve_brk a middle page, figure out which PFNs are "missing" and which
+ + * ones are identity), as that has been done earlier. If we find that the
+ + * middle leaf is not occupied by p2m_identity or p2m_missing, we dereference
+ + * that page (which covers 512 PFNs) and set the appropriate PFN with
+ + * IDENTITY_FRAME_BIT. In our example 263424 and 512256 end up there, and we
+ + * set from p2m[1][2][256->511] and p2m[1][488][0->256] with
+ + * IDENTITY_FRAME_BIT set.
+ + *
+ + * All other regions that are void (or not filled) either point to p2m_missing
+ + * (considered missing) or have the default value of INVALID_P2M_ENTRY (also
+ + * considered missing). In our case, p2m[1][2][0->255] and p2m[1][488][257->511]
+ + * contain the INVALID_P2M_ENTRY value and are considered "missing."
+ + *
+ + * This is what the p2m ends up looking (for the E820 above) with this
+ + * fabulous drawing:
+ + *
+ + * p2m /--------------\
+ + * /-----\ | &mfn_list[0],| /-----------------\
+ + * | 0 |------>| &mfn_list[1],| /---------------\ | ~0, ~0, .. |
+ + * |-----| | ..., ~0, ~0 | | ~0, ~0, [x]---+----->| IDENTITY [@256] |
+ + * | 1 |---\ \--------------/ | [p2m_identity]+\ | IDENTITY [@257] |
+ + * |-----| \ | [p2m_identity]+\\ | .... |
+ + * | 2 |--\ \-------------------->| ... | \\ \----------------/
+ + * |-----| \ \---------------/ \\
+ + * | 3 |\ \ \\ p2m_identity
+ + * |-----| \ \-------------------->/---------------\ /-----------------\
+ + * | .. +->+ | [p2m_identity]+-->| ~0, ~0, ~0, ... |
+ + * \-----/ / | [p2m_identity]+-->| ..., ~0 |
+ + * / /---------------\ | .... | \-----------------/
+ + * / | IDENTITY[@0] | /-+-[x], ~0, ~0.. |
+ + * / | IDENTITY[@256]|<----/ \---------------/
+ + * / | ~0, ~0, .... |
+ + * | \---------------/
+ + * |
+ + * p2m_missing p2m_missing
+ + * /------------------\ /------------\
+ + * | [p2m_mid_missing]+---->| ~0, ~0, ~0 |
+ + * | [p2m_mid_missing]+---->| ..., ~0 |
+ + * \------------------/ \------------/
+ + *
+ + * where ~0 is INVALID_P2M_ENTRY. IDENTITY is (PFN | IDENTITY_BIT)
*/
#include <linux/init.h>
#include <linux/list.h>
#include <linux/hash.h>
#include <linux/sched.h>
+ +#include <linux/seq_file.h>
#include <asm/cache.h>
#include <asm/setup.h>
static RESERVE_BRK_ARRAY(unsigned long, p2m_top_mfn, P2M_TOP_PER_PAGE);
static RESERVE_BRK_ARRAY(unsigned long *, p2m_top_mfn_p, P2M_TOP_PER_PAGE);
+ +static RESERVE_BRK_ARRAY(unsigned long, p2m_identity, P2M_PER_PAGE);
+ +
RESERVE_BRK(p2m_mid, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE)));
RESERVE_BRK(p2m_mid_mfn, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE)));
+ +/* We might hit two boundary violations at the start and end, at max each
+ + * boundary violation will require three middle nodes. */
+ +RESERVE_BRK(p2m_mid_identity, PAGE_SIZE * 2 * 3);
+ +
static inline unsigned p2m_top_index(unsigned long pfn)
{
BUG_ON(pfn >= MAX_P2M_PFN);
p2m_top = extend_brk(PAGE_SIZE, PAGE_SIZE);
p2m_top_init(p2m_top);
+ + p2m_identity = extend_brk(PAGE_SIZE, PAGE_SIZE);
+ + p2m_init(p2m_identity);
+ +
/*
* The domain builder gives us a pre-constructed p2m array in
* mfn_list for all the pages initially given to us, so we just
* As long as the mfn_list has enough entries to completely
* fill a p2m page, pointing into the array is ok. But if
* not the entries beyond the last pfn will be undefined.
- * And guessing that the 'what-ever-there-is' does not take it
- * too kindly when changing it to invalid markers, a new page
- * is allocated, initialized and filled with the valid part.
*/
if (unlikely(pfn + P2M_PER_PAGE > max_pfn)) {
unsigned long p2midx;
- unsigned long *p2m = extend_brk(PAGE_SIZE, PAGE_SIZE);
- p2m_init(p2m);
-
- for (p2midx = 0; pfn + p2midx < max_pfn; p2midx++) {
- p2m[p2midx] = mfn_list[pfn + p2midx];
- }
- p2m_top[topidx][mididx] = p2m;
- } else
- p2m_top[topidx][mididx] = &mfn_list[pfn];
+
+ p2midx = max_pfn % P2M_PER_PAGE;
+ for ( ; p2midx < P2M_PER_PAGE; p2midx++)
+ mfn_list[pfn + p2midx] = INVALID_P2M_ENTRY;
+ }
+ p2m_top[topidx][mididx] = &mfn_list[pfn];
}
m2p_override_init();
mididx = p2m_mid_index(pfn);
idx = p2m_index(pfn);
+ + /*
+ + * The INVALID_P2M_ENTRY is filled in both p2m_*identity
+ + * and in p2m_*missing, so returning the INVALID_P2M_ENTRY
+ + * would be wrong.
+ + */
+ + if (p2m_top[topidx][mididx] == p2m_identity)
+ + return IDENTITY_FRAME(pfn);
+ +
return p2m_top[topidx][mididx][idx];
}
EXPORT_SYMBOL_GPL(get_phys_to_machine);
p2m_top_mfn_p[topidx] = mid_mfn;
}
- - if (p2m_top[topidx][mididx] == p2m_missing) {
+ + if (p2m_top[topidx][mididx] == p2m_identity ||
+ + p2m_top[topidx][mididx] == p2m_missing) {
/* p2m leaf page is missing */
unsigned long *p2m;
+ + unsigned long *p2m_orig = p2m_top[topidx][mididx];
p2m = alloc_p2m_page();
if (!p2m)
p2m_init(p2m);
- - if (cmpxchg(&mid[mididx], p2m_missing, p2m) != p2m_missing)
+ + if (cmpxchg(&mid[mididx], p2m_orig, p2m) != p2m_orig)
free_p2m_page(p2m);
else
mid_mfn[mididx] = virt_to_mfn(p2m);
return true;
}
+ +bool __early_alloc_p2m(unsigned long pfn)
+ +{
+ + unsigned topidx, mididx, idx;
+ +
+ + topidx = p2m_top_index(pfn);
+ + mididx = p2m_mid_index(pfn);
+ + idx = p2m_index(pfn);
+ +
+ + /* Pfff.. No boundary cross-over, lets get out. */
+ + if (!idx)
+ + return false;
+ +
+ + WARN(p2m_top[topidx][mididx] == p2m_identity,
+ + "P2M[%d][%d] == IDENTITY, should be MISSING (or alloced)!\n",
+ + topidx, mididx);
+ +
+ + /*
+ + * Could be done by xen_build_dynamic_phys_to_machine..
+ + */
+ + if (p2m_top[topidx][mididx] != p2m_missing)
+ + return false;
+ +
+ + /* Boundary cross-over for the edges: */
+ + if (idx) {
+ + unsigned long *p2m = extend_brk(PAGE_SIZE, PAGE_SIZE);
+ +
+ + p2m_init(p2m);
+ +
+ + p2m_top[topidx][mididx] = p2m;
+ +
+ + }
+ + return idx != 0;
+ +}
+ +unsigned long set_phys_range_identity(unsigned long pfn_s,
+ + unsigned long pfn_e)
+ +{
+ + unsigned long pfn;
+ +
+ + if (unlikely(pfn_s >= MAX_P2M_PFN || pfn_e >= MAX_P2M_PFN))
+ + return 0;
+ +
+ + if (unlikely(xen_feature(XENFEAT_auto_translated_physmap)))
+ + return pfn_e - pfn_s;
+ +
+ + if (pfn_s > pfn_e)
+ + return 0;
+ +
+ + for (pfn = (pfn_s & ~(P2M_MID_PER_PAGE * P2M_PER_PAGE - 1));
+ + pfn < ALIGN(pfn_e, (P2M_MID_PER_PAGE * P2M_PER_PAGE));
+ + pfn += P2M_MID_PER_PAGE * P2M_PER_PAGE)
+ + {
+ + unsigned topidx = p2m_top_index(pfn);
+ + if (p2m_top[topidx] == p2m_mid_missing) {
+ + unsigned long **mid = extend_brk(PAGE_SIZE, PAGE_SIZE);
+ +
+ + p2m_mid_init(mid);
+ +
+ + p2m_top[topidx] = mid;
+ + }
+ + }
+ +
+ + __early_alloc_p2m(pfn_s);
+ + __early_alloc_p2m(pfn_e);
+ +
+ + for (pfn = pfn_s; pfn < pfn_e; pfn++)
+ + if (!__set_phys_to_machine(pfn, IDENTITY_FRAME(pfn)))
+ + break;
+ +
+ + if (!WARN((pfn - pfn_s) != (pfn_e - pfn_s),
+ + "Identity mapping failed. We are %ld short of 1-1 mappings!\n",
+ + (pfn_e - pfn_s) - (pfn - pfn_s)))
+ + printk(KERN_DEBUG "1-1 mapping on %lx->%lx\n", pfn_s, pfn);
+ +
+ + return pfn - pfn_s;
+ +}
+ +
/* Try to install p2m mapping; fail if intermediate bits missing */
bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
{
unsigned topidx, mididx, idx;
+ + if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
+ + BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
+ + return true;
+ + }
if (unlikely(pfn >= MAX_P2M_PFN)) {
BUG_ON(mfn != INVALID_P2M_ENTRY);
return true;
mididx = p2m_mid_index(pfn);
idx = p2m_index(pfn);
+ + /* For sparse holes were the p2m leaf has real PFN along with
+ + * PCI holes, stick in the PFN as the MFN value.
+ + */
+ + if (mfn != INVALID_P2M_ENTRY && (mfn & IDENTITY_FRAME_BIT)) {
+ + if (p2m_top[topidx][mididx] == p2m_identity)
+ + return true;
+ +
+ + /* Swap over from MISSING to IDENTITY if needed. */
+ + if (p2m_top[topidx][mididx] == p2m_missing) {
+ + WARN_ON(cmpxchg(&p2m_top[topidx][mididx], p2m_missing,
+ + p2m_identity) != p2m_missing);
+ + return true;
+ + }
+ + }
+ +
if (p2m_top[topidx][mididx] == p2m_missing)
return mfn == INVALID_P2M_ENTRY;
bool 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 true;
- - }
- -
if (unlikely(!__set_phys_to_machine(pfn, mfn))) {
if (!alloc_p2m(pfn))
return false;
return ret;
}
EXPORT_SYMBOL_GPL(m2p_find_override_pfn);
+ +
+ +#ifdef CONFIG_XEN_DEBUG_FS
+ +
+ +int p2m_dump_show(struct seq_file *m, void *v)
+ +{
+ + static const char * const level_name[] = { "top", "middle",
+ + "entry", "abnormal" };
+ + static const char * const type_name[] = { "identity", "missing",
+ + "pfn", "abnormal"};
+ +#define TYPE_IDENTITY 0
+ +#define TYPE_MISSING 1
+ +#define TYPE_PFN 2
+ +#define TYPE_UNKNOWN 3
+ + unsigned long pfn, prev_pfn_type = 0, prev_pfn_level = 0;
+ + unsigned int uninitialized_var(prev_level);
+ + unsigned int uninitialized_var(prev_type);
+ +
+ + if (!p2m_top)
+ + return 0;
+ +
+ + for (pfn = 0; pfn < MAX_DOMAIN_PAGES; pfn++) {
+ + unsigned topidx = p2m_top_index(pfn);
+ + unsigned mididx = p2m_mid_index(pfn);
+ + unsigned idx = p2m_index(pfn);
+ + unsigned lvl, type;
+ +
+ + lvl = 4;
+ + type = TYPE_UNKNOWN;
+ + if (p2m_top[topidx] == p2m_mid_missing) {
+ + lvl = 0; type = TYPE_MISSING;
+ + } else if (p2m_top[topidx] == NULL) {
+ + lvl = 0; type = TYPE_UNKNOWN;
+ + } else if (p2m_top[topidx][mididx] == NULL) {
+ + lvl = 1; type = TYPE_UNKNOWN;
+ + } else if (p2m_top[topidx][mididx] == p2m_identity) {
+ + lvl = 1; type = TYPE_IDENTITY;
+ + } else if (p2m_top[topidx][mididx] == p2m_missing) {
+ + lvl = 1; type = TYPE_MISSING;
+ + } else if (p2m_top[topidx][mididx][idx] == 0) {
+ + lvl = 2; type = TYPE_UNKNOWN;
+ + } else if (p2m_top[topidx][mididx][idx] == IDENTITY_FRAME(pfn)) {
+ + lvl = 2; type = TYPE_IDENTITY;
+ + } else if (p2m_top[topidx][mididx][idx] == INVALID_P2M_ENTRY) {
+ + lvl = 2; type = TYPE_MISSING;
+ + } else if (p2m_top[topidx][mididx][idx] == pfn) {
+ + lvl = 2; type = TYPE_PFN;
+ + } else if (p2m_top[topidx][mididx][idx] != pfn) {
+ + lvl = 2; type = TYPE_PFN;
+ + }
+ + if (pfn == 0) {
+ + prev_level = lvl;
+ + prev_type = type;
+ + }
+ + if (pfn == MAX_DOMAIN_PAGES-1) {
+ + lvl = 3;
+ + type = TYPE_UNKNOWN;
+ + }
+ + if (prev_type != type) {
+ + seq_printf(m, " [0x%lx->0x%lx] %s\n",
+ + prev_pfn_type, pfn, type_name[prev_type]);
+ + prev_pfn_type = pfn;
+ + prev_type = type;
+ + }
+ + if (prev_level != lvl) {
+ + seq_printf(m, " [0x%lx->0x%lx] level %s\n",
+ + prev_pfn_level, pfn, level_name[prev_level]);
+ + prev_pfn_level = pfn;
+ + prev_level = lvl;
+ + }
+ + }
+ + return 0;
+ +#undef TYPE_IDENTITY
+ +#undef TYPE_MISSING
+ +#undef TYPE_PFN
+ +#undef TYPE_UNKNOWN
+ +}
+ +#endif
static __init void xen_add_extra_mem(unsigned long pages)
{
+ + unsigned long pfn;
+ +
u64 size = (u64)pages * PAGE_SIZE;
u64 extra_start = xen_extra_mem_start + xen_extra_mem_size;
xen_extra_mem_size += size;
xen_max_p2m_pfn = PFN_DOWN(extra_start + size);
+ +
+ + for (pfn = PFN_DOWN(extra_start); pfn <= xen_max_p2m_pfn; pfn++)
+ + __set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
}
static unsigned long __init xen_release_chunk(phys_addr_t start_addr,
WARN(ret != 1, "Failed to release memory %lx-%lx err=%d\n",
start, end, ret);
if (ret == 1) {
- - set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
+ + __set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
len++;
}
}
return released;
}
+ +static unsigned long __init xen_set_identity(const struct e820entry *list,
+ + ssize_t map_size)
+ +{
+ + phys_addr_t last = xen_initial_domain() ? 0 : ISA_END_ADDRESS;
+ + phys_addr_t start_pci = last;
+ + const struct e820entry *entry;
+ + unsigned long identity = 0;
+ + int i;
+ +
+ + for (i = 0, entry = list; i < map_size; i++, entry++) {
+ + phys_addr_t start = entry->addr;
+ + phys_addr_t end = start + entry->size;
+ +
+ + if (start < last)
+ + start = last;
+ +
+ + if (end <= start)
+ + continue;
+ +
+ + /* Skip over the 1MB region. */
+ + if (last > end)
+ + continue;
+ +
+ + if (entry->type == E820_RAM) {
+ + if (start > start_pci)
+ + identity += set_phys_range_identity(
+ + PFN_UP(start_pci), PFN_DOWN(start));
+ +
+ + /* Without saving 'last' we would gooble RAM too
+ + * at the end of the loop. */
+ + last = end;
+ + start_pci = end;
+ + continue;
+ + }
+ + start_pci = min(start, start_pci);
+ + last = end;
+ + }
+ + if (last > start_pci)
+ + identity += set_phys_range_identity(
+ + PFN_UP(start_pci), PFN_DOWN(last));
+ + return identity;
+ +}
/**
* machine_specific_memory_setup - Hook for machine specific memory setup.
**/
char * __init xen_memory_setup(void)
{
static struct e820entry map[E820MAX] __initdata;
+ + static struct e820entry map_raw[E820MAX] __initdata;
unsigned long max_pfn = xen_start_info->nr_pages;
unsigned long long mem_end;
struct xen_memory_map memmap;
unsigned long extra_pages = 0;
unsigned long extra_limit;
+ + unsigned long identity_pages = 0;
int i;
int op;
}
BUG_ON(rc);
+ + memcpy(map_raw, map, sizeof(map));
e820.nr_map = 0;
xen_extra_mem_start = mem_end;
for (i = 0; i < memmap.nr_entries; i++) {
- unsigned long long end = map[i].addr + map[i].size;
+ unsigned long long end;
+ /* Guard against non-page aligned E820 entries. */
+ if (map[i].type == E820_RAM)
+ map[i].size -= (map[i].size + map[i].addr) % PAGE_SIZE;
+
+ end = map[i].addr + map[i].size;
if (map[i].type == E820_RAM && end > mem_end) {
/* RAM off the end - may be partially included */
u64 delta = min(map[i].size, end - mem_end);
end -= delta;
extra_pages += PFN_DOWN(delta);
++ /*
++ * Set RAM below 4GB that is not for us to be unusable.
++ * This prevents "System RAM" address space from being
++ * used as potential resource for I/O address (happens
++ * when 'allocate_resource' is called).
++ */
++ if (delta &&
++ (xen_initial_domain() && end < 0x100000000ULL))
++ e820_add_region(end, delta, E820_UNUSABLE);
}
if (map[i].size > 0 && end > xen_extra_mem_start)
xen_add_extra_mem(extra_pages);
+ + /*
+ + * Set P2M for all non-RAM pages and E820 gaps to be identity
+ + * type PFNs. We supply it with the non-sanitized version
+ + * of the E820.
+ + */
+ + identity_pages = xen_set_identity(map_raw, memmap.nr_entries);
+ + printk(KERN_INFO "Set %ld page(s) to 1-1 mapping.\n", identity_pages);
return "Xen";
}
boot_cpu_data.hlt_works_ok = 1;
#endif
pm_idle = default_idle;
+ boot_option_idle_override = IDLE_HALT;
fiddle_vdso();
}