]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branches 'stable/p2m-identity.v4.9.1' and 'stable/e820' of git://git.kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 15 Mar 2011 17:32:15 +0000 (10:32 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 15 Mar 2011 17:32:15 +0000 (10:32 -0700)
* 'stable/p2m-identity.v4.9.1' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen:
  xen/m2p: Check whether the MFN has IDENTITY_FRAME bit set..
  xen/m2p: No need to catch exceptions when we know that there is no RAM
  xen/debug: WARN_ON when identity PFN has no _PAGE_IOMAP flag set.
  xen/debugfs: Add 'p2m' file for printing out the P2M layout.
  xen/setup: Set identity mapping for non-RAM E820 and E820 gaps.
  xen/mmu: WARN_ON when racing to swap middle leaf.
  xen/mmu: Set _PAGE_IOMAP if PFN is an identity PFN.
  xen/mmu: Add the notion of identity (1-1) mapping.
  xen: Mark all initial reserved pages for the balloon as INVALID_P2M_ENTRY.

* 'stable/e820' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen:
  xen/e820: Don't mark balloon memory as E820_UNUSABLE when running as guest and fix overflow.
  xen/setup: Inhibit resource API from using System RAM E820 gaps as PCI mem gaps.

1  2  3 
arch/x86/xen/mmu.c
arch/x86/xen/p2m.c
arch/x86/xen/setup.c

diff --combined arch/x86/xen/mmu.c
index f6089421147a0affdc98916081a7fbf54eb70b39,0c376a2d9f9808084f7fade1438c984c4e8cc5fb,5e92b61ad574dd6514f09644737dd450d0311dd0..832765c0fb8c3b22b0712c80e9a9eed4cf4d0103
   #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>
@@@@ -416,8 -417,12 -416,8 +417,12 @@@@ static pteval_t pte_pfn_to_mfn(pteval_
        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;
        }
   
@@@@ -532,6 -547,41 -532,6 +547,41 @@@@ pte_t xen_make_pte(pteval_t pte
   }
   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);
@@@@ -986,9 -1036,10 -986,10 +1036,9 @@@@ static void xen_pgd_pin(struct mm_struc
    */
   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);
   }
   
   /*
@@@@ -1098,9 -1149,10 -1099,10 +1148,9 @@@@ static void xen_pgd_unpin(struct mm_str
    */
   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)
@@@@ -1940,6 -1992,9 -1942,6 +1990,9 @@@@ __init void xen_ident_map_ISA(void
   
   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;
@@@@ -2072,7 -2127,7 -2074,7 +2125,7 @@@@ static void xen_zap_pfn_range(unsigned 
                        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);
@@@@ -2351,6 -2406,18 -2353,6 +2404,18 @@@@ EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_
   
   #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);
diff --combined arch/x86/xen/p2m.c
index fd12d7ce7ff93265ed620ac9ef96db2c676a6c94,65f21f4b3962483ae88fe899313d75239efaf519,fd12d7ce7ff93265ed620ac9ef96db2c676a6c94..00fe5604c5932a4232e022d65a9f441a3dc977f0
    * 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>
@@@@ -59,9 -183,15 -59,9 +183,15 @@@@ static RESERVE_BRK_ARRAY(unsigned long 
   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);
@@@@ -221,6 -351,9 -221,6 +351,9 @@@@ void __init xen_build_dynamic_phys_to_m
        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();
@@@@ -266,6 -405,14 -266,6 +399,14 @@@@ unsigned long get_phys_to_machine(unsig
        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);
@@@@ -335,9 -482,11 -335,9 +476,11 @@@@ static bool alloc_p2m(unsigned long pfn
                        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;
@@@@ -520,3 -759,80 -520,3 +753,80 @@@@ unsigned long m2p_find_override_pfn(uns
        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
diff --combined arch/x86/xen/setup.c
index a8a66a50d446342128776bfae67b27a5b97dd6f4,54d93791ddb964fb3c80d2e0ad5cccabfc60b9ab,010ba2e62de54395e10f137f0448eb8558442375..fa0269a993773f8488f765c3a1e255ba59fd4e3f
@@@@ -52,6 -52,8 -52,6 +52,8 @@@@ phys_addr_t xen_extra_mem_start, xen_ex
   
   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++;
                }
        }
@@@@ -138,12 -143,55 -138,12 +143,55 @@@@ static unsigned long __init xen_return_
        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";
   }
   
@@@@ -355,7 -407,6 -364,7 +421,7 @@@@ void __init xen_arch_setup(void
        boot_cpu_data.hlt_works_ok = 1;
   #endif
        pm_idle = default_idle;
 +      boot_option_idle_override = IDLE_HALT;
   
        fiddle_vdso();
   }