diff options
Diffstat (limited to 'arch/x86/xen/mmu.c')
-rw-r--r-- | arch/x86/xen/mmu.c | 61 |
1 files changed, 44 insertions, 17 deletions
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 0e572380413b..e0a55b7a6ceb 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
@@ -233,47 +233,74 @@ unsigned long get_phys_to_machine(unsigned long pfn) | |||
233 | } | 233 | } |
234 | EXPORT_SYMBOL_GPL(get_phys_to_machine); | 234 | EXPORT_SYMBOL_GPL(get_phys_to_machine); |
235 | 235 | ||
236 | static void alloc_p2m(unsigned long **pp, unsigned long *mfnp) | 236 | /* install a new p2m_top page */ |
237 | bool install_p2mtop_page(unsigned long pfn, unsigned long *p) | ||
237 | { | 238 | { |
238 | unsigned long *p; | 239 | unsigned topidx = p2m_top_index(pfn); |
240 | unsigned long **pfnp, *mfnp; | ||
239 | unsigned i; | 241 | unsigned i; |
240 | 242 | ||
241 | p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL); | 243 | pfnp = &p2m_top[topidx]; |
242 | BUG_ON(p == NULL); | 244 | mfnp = &p2m_top_mfn[topidx]; |
243 | 245 | ||
244 | for (i = 0; i < P2M_ENTRIES_PER_PAGE; i++) | 246 | for (i = 0; i < P2M_ENTRIES_PER_PAGE; i++) |
245 | p[i] = INVALID_P2M_ENTRY; | 247 | p[i] = INVALID_P2M_ENTRY; |
246 | 248 | ||
247 | if (cmpxchg(pp, p2m_missing, p) != p2m_missing) | 249 | if (cmpxchg(pfnp, p2m_missing, p) == p2m_missing) { |
248 | free_page((unsigned long)p); | ||
249 | else | ||
250 | *mfnp = virt_to_mfn(p); | 250 | *mfnp = virt_to_mfn(p); |
251 | return true; | ||
252 | } | ||
253 | |||
254 | return false; | ||
251 | } | 255 | } |
252 | 256 | ||
253 | void set_phys_to_machine(unsigned long pfn, unsigned long mfn) | 257 | static void alloc_p2m(unsigned long pfn) |
254 | { | 258 | { |
255 | unsigned topidx, idx; | 259 | unsigned long *p; |
256 | 260 | ||
257 | if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) { | 261 | p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL); |
258 | BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY); | 262 | BUG_ON(p == NULL); |
259 | return; | 263 | |
260 | } | 264 | if (!install_p2mtop_page(pfn, p)) |
265 | free_page((unsigned long)p); | ||
266 | } | ||
267 | |||
268 | /* Try to install p2m mapping; fail if intermediate bits missing */ | ||
269 | bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn) | ||
270 | { | ||
271 | unsigned topidx, idx; | ||
261 | 272 | ||
262 | if (unlikely(pfn >= MAX_DOMAIN_PAGES)) { | 273 | if (unlikely(pfn >= MAX_DOMAIN_PAGES)) { |
263 | BUG_ON(mfn != INVALID_P2M_ENTRY); | 274 | BUG_ON(mfn != INVALID_P2M_ENTRY); |
264 | return; | 275 | return true; |
265 | } | 276 | } |
266 | 277 | ||
267 | topidx = p2m_top_index(pfn); | 278 | topidx = p2m_top_index(pfn); |
268 | if (p2m_top[topidx] == p2m_missing) { | 279 | if (p2m_top[topidx] == p2m_missing) { |
269 | /* no need to allocate a page to store an invalid entry */ | ||
270 | if (mfn == INVALID_P2M_ENTRY) | 280 | if (mfn == INVALID_P2M_ENTRY) |
271 | return; | 281 | return true; |
272 | alloc_p2m(&p2m_top[topidx], &p2m_top_mfn[topidx]); | 282 | return false; |
273 | } | 283 | } |
274 | 284 | ||
275 | idx = p2m_index(pfn); | 285 | idx = p2m_index(pfn); |
276 | p2m_top[topidx][idx] = mfn; | 286 | p2m_top[topidx][idx] = mfn; |
287 | |||
288 | return true; | ||
289 | } | ||
290 | |||
291 | void set_phys_to_machine(unsigned long pfn, unsigned long mfn) | ||
292 | { | ||
293 | if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) { | ||
294 | BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY); | ||
295 | return; | ||
296 | } | ||
297 | |||
298 | if (unlikely(!__set_phys_to_machine(pfn, mfn))) { | ||
299 | alloc_p2m(pfn); | ||
300 | |||
301 | if (!__set_phys_to_machine(pfn, mfn)) | ||
302 | BUG(); | ||
303 | } | ||
277 | } | 304 | } |
278 | 305 | ||
279 | unsigned long arbitrary_virt_to_mfn(void *vaddr) | 306 | unsigned long arbitrary_virt_to_mfn(void *vaddr) |