static void build_page_tables(pgentry_t *top_table, unsigned long *pt_pfn, void *start_va, void *end_va) { // // *pt_pfn - unused pages already mapped by domain builder (512K+) // carve new page tables/directories from *pt_pfn as needed // start_va - end_va - range of frames to map // struct mmu_update mmu_updates[L1_PAGETABLE_ENTRIES]; int count = 0; while (start_va + PAGE_SIZE <= end_va) { pgentry_t *tab = top_table; unsigned int offset; pgentry_t pte; #if defined(__x86_64__) offset = l4_table_offset((unsigned long)start_va); pte = tab[offset]; if ((pte & _PAGE_PRESENT) == 0) pte = new_pt_page(pt_pfn, tab, offset, L3_FRAME); tab = pte_to_virt(pte); #endif offset = l3_table_offset((unsigned long)start_va); pte = tab[offset]; if ((pte & _PAGE_PRESENT) == 0) pte = new_pt_page(pt_pfn, tab, offset, L2_FRAME); tab = pte_to_virt(pte); offset = l2_table_offset((unsigned long)start_va); pte = tab[offset]; if ((pte & _PAGE_PRESENT) == 0) pte = new_pt_page(pt_pfn, tab, offset, L1_FRAME); tab = pte_to_virt(pte); offset = l1_table_offset((unsigned long)start_va); pte = tab[offset]; if ((pte & _PAGE_PRESENT) == 0) { unsigned long pt_mfn = virt_to_mfn(tab); mmu_updates[count].ptr = ((pgentry_t)pt_mfn << PAGE_SHIFT) + sizeof(pgentry_t)*offset; mmu_updates[count].val = virt_to_mfn(start_va) << PAGE_SHIFT | L1_PROT; count++; } start_va += PAGE_SIZE; if (count == L1_PAGETABLE_ENTRIES || start_va + PAGE_SIZE > end_va) { int rc = HYPERVISOR_mmu_update(mmu_updates, count, 0, DOMID_SELF); if (rc < 0) fatal_error("build_page_tables: mmu_update failed: %d", rc); count = 0; } } }
int gnttab_post_map_adjust(const struct gnttab_map_grant_ref *map, unsigned int count) { unsigned int i; int rc = 0; for (i = 0; i < count && rc == 0; ++i, ++map) { pte_t pte; if (!(map->flags & GNTMAP_host_map) || !(map->flags & GNTMAP_application_map)) continue; #ifdef CONFIG_X86 pte = __pte_ma((map->dev_bus_addr | _PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_NX | _PAGE_SPECIAL) & __supported_pte_mask); #else #error Architecture not yet supported. #endif if (!(map->flags & GNTMAP_readonly)) pte = pte_mkwrite(pte); if (map->flags & GNTMAP_contains_pte) { mmu_update_t u; u.ptr = map->host_addr; u.val = __pte_val(pte); rc = HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF); } else rc = HYPERVISOR_update_va_mapping(map->host_addr, pte, 0); } return rc; }
static int privcmd_HYPERVISOR_mmu_update(mmu_update_t *ureq, int count, int *scount, domid_t domid) { mmu_update_t *kreq, single_kreq; import_export_t cnt_ie, req_ie; int error, kscount, bytes; bytes = count * sizeof (*kreq); kreq = (count == 1) ? &single_kreq : kmem_alloc(bytes, KM_SLEEP); error = import_buffer(&cnt_ie, scount, &kscount, sizeof (kscount), IE_IMPEXP); if (error != 0) req_ie = null_ie; else error = import_buffer(&req_ie, ureq, kreq, bytes, IE_IMPEXP); DTRACE_XPV3(mmu__update__start, int, domid, int, count, mmu_update_t *, ((error == -X_EFAULT) ? ureq : kreq)); if (error == 0) error = HYPERVISOR_mmu_update(kreq, count, &kscount, domid); export_buffer(&cnt_ie, &error); export_buffer(&req_ie, &error); if (count != 1) kmem_free(kreq, bytes); DTRACE_XPV1(mmu__update__end, int, error); return (error); }
void my_xen_l3_entry_update(pud_t *ptr, pud_t val) { if(aim!=xen_l3_entry_update_id || signal==0) jprobe_return(); if(leave==1) {BUG_ON(HYPERVISOR_mmu_update(&mmuupdateop, 1, NULL, DOMID_SELF) < 0);leave=0;} if(time>0) --time; else {signal=0;printk("Done.\n");jprobe_return();} printk("Fortune: xen_l3_entry_update from %s\n",current->comm); printk("Fortune: pud=0x%llx\tval=0x%llx\n",ptr->pgd.pgd,val.pgd.pgd); printk("Fortune: pud real=0x%llx\n",virt_to_machine(ptr)); mmuupdateop.ptr = virt_to_machine(ptr); mmuupdateop.val = val.pgd.pgd; if(fault==0) { getrando(64); mmuupdateop.ptr ^= (1 << rando); printk("Fortune: change ptr to 0x%llx\n",mmuupdateop.ptr); leave=1; } if(fault==1) { getrando(64); ptr->pgd.pgd ^= (1 << rando); printk("Fortune: change pud to 0x%llx\n",ptr->pgd.pgd); //not need to leave=1 } if(fault==2) { getrando(64); mmuupdateop.val ^= (1 << rando); printk("Fortune: change val to 0x%llx\n",mmuupdateop.val); leave=1; } jprobe_return(); }
void my_xen_l2_entry_update(pmd_t *ptr, pmd_t val) { if(aim!=xen_l2_entry_update_id || signal==0) jprobe_return(); if(leave==1) {BUG_ON(HYPERVISOR_mmu_update(&mmuupdateop, 1, NULL, DOMID_SELF) < 0);leave=0;} //if((strcmp(current->comm,"xm")==0)||(strcmp(current->comm,"xend")==0)) printk("Fortune: %s\n",current->comm); else jprobe_return(); if(time>0) --time; else {signal=0;printk("Done.\n");jprobe_return();} printk("Fortune: xen_l2_entry_update from %s\n",current->comm); printk("Fortune: pmd=0x%llx\tval=0x%llx\n",ptr->pmd,val.pmd); printk("Fortune: ptr real=0x%llx\n",virt_to_machine(ptr)); mmuupdateop.ptr = virt_to_machine(ptr); mmuupdateop.val = pmd_val_ma(val); if(fault==0) { getrando(64); mmuupdateop.ptr ^= (1 << rando); printk("Fortune: change ptr to 0x%llx\n",mmuupdateop.ptr); leave=1; } if(fault==1) { getrando(64); ptr->pmd ^= (1 << rando); printk("Fortune: change pmd to 0x%llx\n",ptr->pmd); //not need to leave=1 } if(fault==2) { getrando(64); mmuupdateop.val ^= (1 << rando); printk("Fortune: change val to 0x%llx\n",mmuupdateop.val); leave=1; } jprobe_return(); }
void xen_l4_entry_update(pgd_t *ptr, pgd_t val) { mmu_update_t u; u.ptr = virt_to_machine(ptr); u.val = val.pgd; BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0); }
void xen_l3_entry_update(pud_t *ptr, pud_t val) { mmu_update_t u; u.ptr = virt_to_machine(ptr); u.val = pud_val_ma(val); BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0); }
void xen_machphys_update(unsigned long mfn, unsigned long pfn) { mmu_update_t u; if (xen_feature(XENFEAT_auto_translated_physmap)) { BUG_ON(pfn != mfn); return; } u.ptr = ((unsigned long long)mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE; u.val = pfn; BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0); }
int xpq_update_foreign(paddr_t ptr, pt_entry_t val, int dom) { mmu_update_t op; int ok; xpq_flush_queue(); op.ptr = ptr; op.val = val; if (HYPERVISOR_mmu_update(&op, 1, &ok, dom) < 0) return EFAULT; return (0); }
static pgentry_t new_pt_page(unsigned long *pt_pfn, pgentry_t *higher_tab, unsigned int higher_off, int level) { // *pt_pfn is already mapped by domain builder // remap *pt_pfn as readonly, suitable for page table/directory // update higher_tab[higher_off] with reference to *pt_pfn // (*pt_pfn)++; pgentry_t prot_e, prot_t; prot_e = prot_t = 0; switch ( level ) { case L1_FRAME: prot_e = L1_PROT; prot_t = L2_PROT; break; case L2_FRAME: prot_e = L2_PROT; prot_t = L3_PROT; break; #if defined(__x86_64__) case L3_FRAME: prot_e = L3_PROT; prot_t = L4_PROT; break; #endif default: fatal_error("new_pt_page: level?"); } void *pt_va = pfn_to_virt(*pt_pfn); memset(pt_va, 0, PAGE_SIZE); // all entries not present unsigned long pte0 = pfn_to_mfn(*pt_pfn) << PAGE_SHIFT | (prot_e & ~_PAGE_RW); HYPERVISOR_update_va_mapping((unsigned long)pt_va, __pte(pte0), UVMF_INVLPG); pgentry_t pte = (pfn_to_mfn(*pt_pfn) << PAGE_SHIFT) | prot_t; struct mmu_update mu; mu.ptr = (virt_to_mfn(higher_tab) << PAGE_SHIFT) + sizeof(pgentry_t)*higher_off; mu.val = pte; HYPERVISOR_mmu_update(&mu, 1, 0, DOMID_SELF); (*pt_pfn)++; return pte; }
/*ARGSUSED*/ void set_pteval(paddr_t table, uint_t index, uint_t level, x86pte_t pteval) { #ifdef __xpv mmu_update_t t; maddr_t mtable = pa_to_ma(table); int retcnt; t.ptr = (mtable + index * pte_size) | MMU_NORMAL_PT_UPDATE; t.val = pteval; if (HYPERVISOR_mmu_update(&t, 1, &retcnt, DOMID_SELF) || retcnt != 1) dboot_panic("HYPERVISOR_mmu_update() failed"); #else /* __xpv */ uintptr_t tab_addr = (uintptr_t)table; if (pae_support) ((x86pte_t *)tab_addr)[index] = pteval; else ((x86pte32_t *)tab_addr)[index] = (x86pte32_t)pteval; if (level == top_level && level == 2) reload_cr3(); #endif /* __xpv */ }
/* * Make pt_pfn a new 'level' page table frame and hook it into the page * table at offset in previous level MFN (pref_l_mfn). pt_pfn is a guest * PFN. */ static void new_pt_frame(unsigned long *pt_pfn, unsigned long prev_l_mfn, unsigned long offset, unsigned long level) { pgentry_t *tab = (pgentry_t *)start_info.pt_base; unsigned long pt_page = (unsigned long)pfn_to_virt(*pt_pfn); pgentry_t prot_e, prot_t; mmu_update_t mmu_updates[1]; int rc; prot_e = prot_t = 0; DEBUG("Allocating new L%d pt frame for pfn=%lx, " "prev_l_mfn=%lx, offset=%lx", level, *pt_pfn, prev_l_mfn, offset); /* We need to clear the page, otherwise we might fail to map it as a page table page */ memset((void*) pt_page, 0, PAGE_SIZE); switch ( level ) { case L1_FRAME: prot_e = L1_PROT; prot_t = L2_PROT; break; case L2_FRAME: prot_e = L2_PROT; prot_t = L3_PROT; break; #if defined(__x86_64__) case L3_FRAME: prot_e = L3_PROT; prot_t = L4_PROT; break; #endif default: printk("new_pt_frame() called with invalid level number %d\n", level); do_exit(); break; } /* Make PFN a page table page */ #if defined(__x86_64__) tab = pte_to_virt(tab[l4_table_offset(pt_page)]); #endif tab = pte_to_virt(tab[l3_table_offset(pt_page)]); mmu_updates[0].ptr = (tab[l2_table_offset(pt_page)] & PAGE_MASK) + sizeof(pgentry_t) * l1_table_offset(pt_page); mmu_updates[0].val = (pgentry_t)pfn_to_mfn(*pt_pfn) << PAGE_SHIFT | (prot_e & ~_PAGE_RW); if ( (rc = HYPERVISOR_mmu_update(mmu_updates, 1, NULL, DOMID_SELF)) < 0 ) { printk("ERROR: PTE for new page table page could not be updated\n"); printk(" mmu_update failed with rc=%d\n", rc); do_exit(); } /* Hook the new page table page into the hierarchy */ mmu_updates[0].ptr = ((pgentry_t)prev_l_mfn << PAGE_SHIFT) + sizeof(pgentry_t) * offset; mmu_updates[0].val = (pgentry_t)pfn_to_mfn(*pt_pfn) << PAGE_SHIFT | prot_t; if ( (rc = HYPERVISOR_mmu_update(mmu_updates, 1, NULL, DOMID_SELF)) < 0 ) { printk("ERROR: mmu_update failed with rc=%d\n", rc); do_exit(); } *pt_pfn += 1; }
/* * Must not be called with IRQs off. This should only be used on the * slow path. * * Copy a foreign granted page to local memory. */ int gnttab_copy_grant_page(grant_ref_t ref, struct page **pagep) { struct gnttab_unmap_and_replace unmap; mmu_update_t mmu; struct page *page; struct page *new_page; void *new_addr; void *addr; paddr_t pfn; maddr_t mfn; maddr_t new_mfn; int err; page = *pagep; if (!get_page_unless_zero(page)) return -ENOENT; err = -ENOMEM; new_page = alloc_page(GFP_ATOMIC | __GFP_NOWARN); if (!new_page) goto out; new_addr = page_address(new_page); addr = page_address(page); copy_page(new_addr, addr); pfn = page_to_pfn(page); mfn = pfn_to_mfn(pfn); new_mfn = virt_to_mfn(new_addr); write_seqlock_bh(&gnttab_dma_lock); /* Make seq visible before checking page_mapped. */ smp_mb(); /* Has the page been DMA-mapped? */ if (unlikely(page_mapped(page))) { write_sequnlock_bh(&gnttab_dma_lock); put_page(new_page); err = -EBUSY; goto out; } if (!xen_feature(XENFEAT_auto_translated_physmap)) set_phys_to_machine(pfn, new_mfn); gnttab_set_replace_op(&unmap, (unsigned long)addr, (unsigned long)new_addr, ref); err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace, &unmap, 1); BUG_ON(err); BUG_ON(unmap.status != GNTST_okay); write_sequnlock_bh(&gnttab_dma_lock); if (!xen_feature(XENFEAT_auto_translated_physmap)) { set_phys_to_machine(page_to_pfn(new_page), INVALID_P2M_ENTRY); mmu.ptr = (new_mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE; mmu.val = pfn; err = HYPERVISOR_mmu_update(&mmu, 1, NULL, DOMID_SELF); BUG_ON(err); } new_page->mapping = page->mapping; new_page->index = page->index; set_bit(PG_foreign, &new_page->flags); if (PageReserved(page)) SetPageReserved(new_page); *pagep = new_page; SetPageForeign(page, gnttab_page_free); page->mapping = NULL; out: put_page(page); return err; }
void kexec(void *kernel, long kernel_size, void *module, long module_size, char *cmdline, unsigned long flags) { struct xc_dom_image *dom; int rc; domid_t domid = DOMID_SELF; xen_pfn_t pfn; xc_interface *xc_handle; unsigned long i; void *seg; xen_pfn_t boot_page_mfn = virt_to_mfn(&_boot_page); char features[] = ""; struct mmu_update *m2p_updates; unsigned long nr_m2p_updates; DEBUG("booting with cmdline %s\n", cmdline); xc_handle = xc_interface_open(0,0,0); dom = xc_dom_allocate(xc_handle, cmdline, features); dom->allocate = kexec_allocate; /* We are using guest owned memory, therefore no limits. */ xc_dom_kernel_max_size(dom, 0); xc_dom_ramdisk_max_size(dom, 0); dom->kernel_blob = kernel; dom->kernel_size = kernel_size; dom->ramdisk_blob = module; dom->ramdisk_size = module_size; dom->flags = flags; dom->console_evtchn = start_info.console.domU.evtchn; dom->xenstore_evtchn = start_info.store_evtchn; tpm_hash2pcr(dom, cmdline); if ( (rc = xc_dom_boot_xen_init(dom, xc_handle, domid)) != 0 ) { grub_printf("xc_dom_boot_xen_init returned %d\n", rc); errnum = ERR_BOOT_FAILURE; goto out; } if ( (rc = xc_dom_parse_image(dom)) != 0 ) { grub_printf("xc_dom_parse_image returned %d\n", rc); errnum = ERR_BOOT_FAILURE; goto out; } #ifdef __i386__ if (strcmp(dom->guest_type, "xen-3.0-x86_32p")) { grub_printf("can only boot x86 32 PAE kernels, not %s\n", dom->guest_type); errnum = ERR_EXEC_FORMAT; goto out; } #endif #ifdef __x86_64__ if (strcmp(dom->guest_type, "xen-3.0-x86_64")) { grub_printf("can only boot x86 64 kernels, not %s\n", dom->guest_type); errnum = ERR_EXEC_FORMAT; goto out; } #endif /* equivalent of xc_dom_mem_init */ dom->arch_hooks = xc_dom_find_arch_hooks(xc_handle, dom->guest_type); dom->total_pages = start_info.nr_pages; /* equivalent of arch_setup_meminit */ /* setup initial p2m */ dom->p2m_host = malloc(sizeof(*dom->p2m_host) * dom->total_pages); /* Start with our current P2M */ for (i = 0; i < dom->total_pages; i++) dom->p2m_host[i] = pfn_to_mfn(i); if ( (rc = xc_dom_build_image(dom)) != 0 ) { grub_printf("xc_dom_build_image returned %d\n", rc); errnum = ERR_BOOT_FAILURE; goto out; } /* copy hypercall page */ /* TODO: domctl instead, but requires privileges */ if (dom->parms.virt_hypercall != -1) { pfn = PHYS_PFN(dom->parms.virt_hypercall - dom->parms.virt_base); memcpy((void *) pages[pfn], hypercall_page, PAGE_SIZE); } /* Equivalent of xc_dom_boot_image */ dom->shared_info_mfn = PHYS_PFN(start_info.shared_info); if (!xc_dom_compat_check(dom)) { grub_printf("xc_dom_compat_check failed\n"); errnum = ERR_EXEC_FORMAT; goto out; } /* Move current console, xenstore and boot MFNs to the allocated place */ do_exchange(dom, dom->console_pfn, start_info.console.domU.mfn); do_exchange(dom, dom->xenstore_pfn, start_info.store_mfn); DEBUG("virt base at %llx\n", dom->parms.virt_base); DEBUG("bootstack_pfn %lx\n", dom->bootstack_pfn); _boot_target = dom->parms.virt_base + PFN_PHYS(dom->bootstack_pfn); DEBUG("_boot_target %lx\n", _boot_target); do_exchange(dom, PHYS_PFN(_boot_target - dom->parms.virt_base), virt_to_mfn(&_boot_page)); /* Make sure the bootstrap page table does not RW-map any of our current * page table frames */ kexec_allocate(dom, dom->virt_pgtab_end); if ( (rc = xc_dom_update_guest_p2m(dom))) { grub_printf("xc_dom_update_guest_p2m returned %d\n", rc); errnum = ERR_BOOT_FAILURE; goto out; } if ( dom->arch_hooks->setup_pgtables ) if ( (rc = dom->arch_hooks->setup_pgtables(dom))) { grub_printf("setup_pgtables returned %d\n", rc); errnum = ERR_BOOT_FAILURE; goto out; } /* start info page */ #undef start_info if ( dom->arch_hooks->start_info ) dom->arch_hooks->start_info(dom); #define start_info (start_info_union.start_info) xc_dom_log_memory_footprint(dom); /* Unmap libxc's projection of the boot page table */ seg = xc_dom_seg_to_ptr(dom, &dom->pgtables_seg); munmap(seg, dom->pgtables_seg.vend - dom->pgtables_seg.vstart); /* Unmap day0 pages to avoid having a r/w mapping of the future page table */ for (pfn = 0; pfn < allocated; pfn++) munmap((void*) pages[pfn], PAGE_SIZE); /* Pin the boot page table base */ if ( (rc = pin_table(dom->xch, #ifdef __i386__ MMUEXT_PIN_L3_TABLE, #endif #ifdef __x86_64__ MMUEXT_PIN_L4_TABLE, #endif xc_dom_p2m_host(dom, dom->pgtables_seg.pfn), dom->guest_domid)) != 0 ) { grub_printf("pin_table(%lx) returned %d\n", xc_dom_p2m_host(dom, dom->pgtables_seg.pfn), rc); errnum = ERR_BOOT_FAILURE; goto out_remap; } /* We populate the Mini-OS page table here so that boot.S can just call * update_va_mapping to project itself there. */ need_pgt(_boot_target); DEBUG("day0 pages %lx\n", allocated); DEBUG("boot target page %lx\n", _boot_target); DEBUG("boot page %p\n", &_boot_page); DEBUG("boot page mfn %lx\n", boot_page_mfn); _boot_page_entry = PFN_PHYS(boot_page_mfn) | L1_PROT; DEBUG("boot page entry %llx\n", _boot_page_entry); _boot_oldpdmfn = virt_to_mfn(start_info.pt_base); DEBUG("boot old pd mfn %lx\n", _boot_oldpdmfn); DEBUG("boot pd virt %lx\n", dom->pgtables_seg.vstart); _boot_pdmfn = dom->p2m_host[PHYS_PFN(dom->pgtables_seg.vstart - dom->parms.virt_base)]; DEBUG("boot pd mfn %lx\n", _boot_pdmfn); _boot_stack = _boot_target + PAGE_SIZE; DEBUG("boot stack %lx\n", _boot_stack); _boot_start_info = dom->parms.virt_base + PFN_PHYS(dom->start_info_pfn); DEBUG("boot start info %lx\n", _boot_start_info); _boot_start = dom->parms.virt_entry; DEBUG("boot start %lx\n", _boot_start); /* Keep only useful entries */ for (nr_m2p_updates = pfn = 0; pfn < start_info.nr_pages; pfn++) if (dom->p2m_host[pfn] != pfn_to_mfn(pfn)) nr_m2p_updates++; m2p_updates = malloc(sizeof(*m2p_updates) * nr_m2p_updates); for (i = pfn = 0; pfn < start_info.nr_pages; pfn++) if (dom->p2m_host[pfn] != pfn_to_mfn(pfn)) { m2p_updates[i].ptr = PFN_PHYS(dom->p2m_host[pfn]) | MMU_MACHPHYS_UPDATE; m2p_updates[i].val = pfn; i++; } for (i = 0; i < blk_nb; i++) shutdown_blkfront(blk_dev[i]); if (net_dev) shutdown_netfront(net_dev); if (kbd_dev) shutdown_kbdfront(kbd_dev); stop_kernel(); /* Update M2P */ if ((rc = HYPERVISOR_mmu_update(m2p_updates, nr_m2p_updates, NULL, DOMID_SELF)) < 0) { xprintk("Could not update M2P\n"); ASSERT(0); } xprintk("go!\n"); /* Jump to trampoline boot page */ _boot(); ASSERT(0); out_remap: for (pfn = 0; pfn < allocated; pfn++) do_map_frames(pages[pfn], &pages_mfns[pfn], 1, 0, 0, DOMID_SELF, 0, L1_PROT); out: xc_dom_release(dom); for (pfn = 0; pfn < allocated; pfn++) free_page((void*)pages[pfn]); free(pages); free(pages_mfns); pages = NULL; pages_mfns = NULL; allocated = 0; xc_interface_close(xc_handle ); }
/* * Helper function to update the p2m and m2p tables and kernel mapping. */ static void __init xen_update_mem_tables(unsigned long pfn, unsigned long mfn) { struct mmu_update update = { .ptr = ((uint64_t)mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE, .val = pfn }; /* Update p2m */ if (!set_phys_to_machine(pfn, mfn)) { WARN(1, "Failed to set p2m mapping for pfn=%ld mfn=%ld\n", pfn, mfn); BUG(); } /* Update m2p */ if (HYPERVISOR_mmu_update(&update, 1, NULL, DOMID_SELF) < 0) { WARN(1, "Failed to set m2p mapping for mfn=%ld pfn=%ld\n", mfn, pfn); BUG(); } /* Update kernel mapping, but not for highmem. */ if (pfn >= PFN_UP(__pa(high_memory - 1))) return; if (HYPERVISOR_update_va_mapping((unsigned long)__va(pfn << PAGE_SHIFT), mfn_pte(mfn, PAGE_KERNEL), 0)) { WARN(1, "Failed to update kernel mapping for mfn=%ld pfn=%ld\n", mfn, pfn); BUG(); } } /* * This function updates the p2m and m2p tables with an identity map from * start_pfn to start_pfn+size and prepares remapping the underlying RAM of the * original allocation at remap_pfn. The information needed for remapping is * saved in the memory itself to avoid the need for allocating buffers. The * complete remap information is contained in a list of MFNs each containing * up to REMAP_SIZE MFNs and the start target PFN for doing the remap. * This enables us to preserve the original mfn sequence while doing the * remapping at a time when the memory management is capable of allocating * virtual and physical memory in arbitrary amounts, see 'xen_remap_memory' and * its callers. */ static void __init xen_do_set_identity_and_remap_chunk( unsigned long start_pfn, unsigned long size, unsigned long remap_pfn) { unsigned long buf = (unsigned long)&xen_remap_buf; unsigned long mfn_save, mfn; unsigned long ident_pfn_iter, remap_pfn_iter; unsigned long ident_end_pfn = start_pfn + size; unsigned long left = size; unsigned int i, chunk; WARN_ON(size == 0); BUG_ON(xen_feature(XENFEAT_auto_translated_physmap)); mfn_save = virt_to_mfn(buf); for (ident_pfn_iter = start_pfn, remap_pfn_iter = remap_pfn; ident_pfn_iter < ident_end_pfn; ident_pfn_iter += REMAP_SIZE, remap_pfn_iter += REMAP_SIZE) { chunk = (left < REMAP_SIZE) ? left : REMAP_SIZE; /* Map first pfn to xen_remap_buf */ mfn = pfn_to_mfn(ident_pfn_iter); set_pte_mfn(buf, mfn, PAGE_KERNEL); /* Save mapping information in page */ xen_remap_buf.next_area_mfn = xen_remap_mfn; xen_remap_buf.target_pfn = remap_pfn_iter; xen_remap_buf.size = chunk; for (i = 0; i < chunk; i++) xen_remap_buf.mfns[i] = pfn_to_mfn(ident_pfn_iter + i); /* Put remap buf into list. */ xen_remap_mfn = mfn; /* Set identity map */ set_phys_range_identity(ident_pfn_iter, ident_pfn_iter + chunk); left -= chunk; } /* Restore old xen_remap_buf mapping */ set_pte_mfn(buf, mfn_save, PAGE_KERNEL); }
void __init adjust_boot_vcpu_info(void) { unsigned long lpfn, rpfn, lmfn, rmfn; pte_t *lpte, *rpte; unsigned int level; mmu_update_t mmu[2]; /* * setup_vcpu_info() cannot be used more than once for a given (v)CPU, * hence we must swap the underlying MFNs of the two pages holding old * and new vcpu_info of the boot CPU. * * Do *not* use __get_cpu_var() or percpu_{write,...}() here, as the per- * CPU segment didn't get reloaded yet. Using percpu_read(), as in * arch_use_lazy_mmu_mode(), though undesirable, is safe except for the * accesses to variables that were updated in setup_percpu_areas(). */ lpte = lookup_address((unsigned long)&per_cpu_var(vcpu_info) + (__per_cpu_load - __per_cpu_start), &level); rpte = lookup_address((unsigned long)&per_cpu(vcpu_info, 0), &level); BUG_ON(!lpte || !(pte_flags(*lpte) & _PAGE_PRESENT)); BUG_ON(!rpte || !(pte_flags(*rpte) & _PAGE_PRESENT)); lmfn = __pte_mfn(*lpte); rmfn = __pte_mfn(*rpte); if (lmfn == rmfn) return; lpfn = mfn_to_local_pfn(lmfn); rpfn = mfn_to_local_pfn(rmfn); printk(KERN_INFO "Swapping MFNs for PFN %lx and %lx (MFN %lx and %lx)\n", lpfn, rpfn, lmfn, rmfn); xen_l1_entry_update(lpte, pfn_pte_ma(rmfn, pte_pgprot(*lpte))); xen_l1_entry_update(rpte, pfn_pte_ma(lmfn, pte_pgprot(*rpte))); #ifdef CONFIG_X86_64 if (HYPERVISOR_update_va_mapping((unsigned long)__va(lpfn<<PAGE_SHIFT), pfn_pte_ma(rmfn, PAGE_KERNEL_RO), 0)) BUG(); #endif if (HYPERVISOR_update_va_mapping((unsigned long)__va(rpfn<<PAGE_SHIFT), pfn_pte_ma(lmfn, PAGE_KERNEL), UVMF_TLB_FLUSH)) BUG(); set_phys_to_machine(lpfn, rmfn); set_phys_to_machine(rpfn, lmfn); mmu[0].ptr = ((uint64_t)lmfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE; mmu[0].val = rpfn; mmu[1].ptr = ((uint64_t)rmfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE; mmu[1].val = lpfn; if (HYPERVISOR_mmu_update(mmu, 2, NULL, DOMID_SELF)) BUG(); /* * Copy over all contents of the page just replaced, except for the * vcpu_info itself, as it may have got updated after having been * copied from __per_cpu_load[]. */ memcpy(__va(rpfn << PAGE_SHIFT), __va(lpfn << PAGE_SHIFT), (unsigned long)&per_cpu_var(vcpu_info) & (PAGE_SIZE - 1)); level = (unsigned long)(&per_cpu_var(vcpu_info) + 1) & (PAGE_SIZE - 1); if (level) memcpy(__va(rpfn << PAGE_SHIFT) + level, __va(lpfn << PAGE_SHIFT) + level, PAGE_SIZE - level); }