unsigned long get_phys_to_machine(unsigned long pfn) { unsigned topidx, idx; if (unlikely(pfn >= MAX_DOMAIN_PAGES)) return INVALID_P2M_ENTRY; topidx = p2m_top_index(pfn); idx = p2m_index(pfn); return p2m_top[topidx][idx]; }
unsigned long get_phys_to_machine(unsigned long pfn) { unsigned topidx, mididx, idx; if (unlikely(pfn >= MAX_P2M_PFN)) return INVALID_P2M_ENTRY; topidx = p2m_top_index(pfn); mididx = p2m_mid_index(pfn); idx = p2m_index(pfn); if (p2m_top[topidx][mididx] == p2m_identity) return IDENTITY_FRAME(pfn); return p2m_top[topidx][mididx][idx]; }
static bool __init early_alloc_p2m_middle(unsigned long pfn, bool check_boundary) { unsigned topidx, mididx, idx; unsigned long *p2m; unsigned long *mid_mfn_p; topidx = p2m_top_index(pfn); mididx = p2m_mid_index(pfn); idx = p2m_index(pfn); /* Pfff.. No boundary cross-over, lets get out. */ if (!idx && check_boundary) 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: */ p2m = extend_brk(PAGE_SIZE, PAGE_SIZE); p2m_init(p2m); p2m_top[topidx][mididx] = p2m; /* For save/restore we need to MFN of the P2M saved */ mid_mfn_p = p2m_top_mfn_p[topidx]; WARN(mid_mfn_p[mididx] != virt_to_mfn(p2m_missing), "P2M_TOP_P[%d][%d] != MFN of p2m_missing!\n", topidx, mididx); mid_mfn_p[mididx] = virt_to_mfn(p2m); return true; }
/* 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; }
unsigned long get_phys_to_machine(unsigned long pfn) { unsigned topidx, mididx, idx; if (unlikely(pfn >= MAX_P2M_PFN)) return INVALID_P2M_ENTRY; topidx = p2m_top_index(pfn); 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]; }
/* 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; } topidx = p2m_top_index(pfn); 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; p2m_top[topidx][mididx][idx] = mfn; return true; }
static bool __init __early_alloc_p2m(unsigned long pfn) { unsigned topidx, mididx, idx; topidx = p2m_top_index(pfn); mididx = p2m_mid_index(pfn); idx = p2m_index(pfn); if (!idx) return false; WARN(p2m_top[topidx][mididx] == p2m_identity, "P2M[%d][%d] == IDENTITY, should be MISSING (or alloced)!\n", topidx, mididx); if (p2m_top[topidx][mididx] != p2m_missing) return false; if (idx) { unsigned long *p2m = extend_brk(PAGE_SIZE, PAGE_SIZE); unsigned long *mid_mfn_p; p2m_init(p2m); p2m_top[topidx][mididx] = p2m; mid_mfn_p = p2m_top_mfn_p[topidx]; WARN(mid_mfn_p[mididx] != virt_to_mfn(p2m_missing), "P2M_TOP_P[%d][%d] != MFN of p2m_missing!\n", topidx, mididx); mid_mfn_p[mididx] = virt_to_mfn(p2m); } return idx != 0; }
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; } topidx = p2m_top_index(pfn); mididx = p2m_mid_index(pfn); idx = p2m_index(pfn); if (mfn != INVALID_P2M_ENTRY && (mfn & IDENTITY_FRAME_BIT)) { if (p2m_top[topidx][mididx] == p2m_identity) return true; 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; p2m_top[topidx][mididx][idx] = mfn; return true; }
static int p2m_dump_show(struct seq_file *m, void *v) { static const char * const level_name[] = { "top", "middle", "entry", "abnormal", "error"}; #define TYPE_IDENTITY 0 #define TYPE_MISSING 1 #define TYPE_PFN 2 #define TYPE_UNKNOWN 3 static const char * const type_name[] = { [TYPE_IDENTITY] = "identity", [TYPE_MISSING] = "missing", [TYPE_PFN] = "pfn", [TYPE_UNKNOWN] = "abnormal"}; 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 }
/* * Skim over the P2M tree looking at pages that are either filled with * INVALID_P2M_ENTRY or with 1:1 PFNs. If found, re-use that page and * replace the P2M leaf with a p2m_missing or p2m_identity. * Stick the old page in the new P2M tree location. */ bool __init early_can_reuse_p2m_middle(unsigned long set_pfn, unsigned long set_mfn) { unsigned topidx; unsigned mididx; unsigned ident_pfns; unsigned inv_pfns; unsigned long *p2m; unsigned long *mid_mfn_p; unsigned idx; unsigned long pfn; /* We only look when this entails a P2M middle layer */ if (p2m_index(set_pfn)) return false; for (pfn = 0; pfn <= MAX_DOMAIN_PAGES; pfn += P2M_PER_PAGE) { topidx = p2m_top_index(pfn); if (!p2m_top[topidx]) continue; if (p2m_top[topidx] == p2m_mid_missing) continue; mididx = p2m_mid_index(pfn); p2m = p2m_top[topidx][mididx]; if (!p2m) continue; if ((p2m == p2m_missing) || (p2m == p2m_identity)) continue; if ((unsigned long)p2m == INVALID_P2M_ENTRY) continue; ident_pfns = 0; inv_pfns = 0; for (idx = 0; idx < P2M_PER_PAGE; idx++) { /* IDENTITY_PFNs are 1:1 */ if (p2m[idx] == IDENTITY_FRAME(pfn + idx)) ident_pfns++; else if (p2m[idx] == INVALID_P2M_ENTRY) inv_pfns++; else break; } if ((ident_pfns == P2M_PER_PAGE) || (inv_pfns == P2M_PER_PAGE)) goto found; } return false; found: /* Found one, replace old with p2m_identity or p2m_missing */ p2m_top[topidx][mididx] = (ident_pfns ? p2m_identity : p2m_missing); /* And the other for save/restore.. */ mid_mfn_p = p2m_top_mfn_p[topidx]; /* NOTE: Even if it is a p2m_identity it should still be point to * a page filled with INVALID_P2M_ENTRY entries. */ mid_mfn_p[mididx] = virt_to_mfn(p2m_missing); /* Reset where we want to stick the old page in. */ topidx = p2m_top_index(set_pfn); mididx = p2m_mid_index(set_pfn); /* This shouldn't happen */ if (WARN_ON(p2m_top[topidx] == p2m_mid_missing)) early_alloc_p2m(set_pfn); if (WARN_ON(p2m_top[topidx][mididx] != p2m_missing)) return false; p2m_init(p2m); p2m_top[topidx][mididx] = p2m; mid_mfn_p = p2m_top_mfn_p[topidx]; mid_mfn_p[mididx] = virt_to_mfn(p2m); return true; }