arch/x86/xen/mmu_pv.c

Source file repositories/reference/linux-study-clean/arch/x86/xen/mmu_pv.c

File Facts

System
Linux kernel
Corpus path
arch/x86/xen/mmu_pv.c
Extension
.c
Size
67438 bytes
Lines
2558
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

* The generic code starts (start_kernel) and 'init_mem_mapping' sets
 * up the rest of the pagetables. When it has completed it loads the cr3.
 * N.B. that baremetal would start at 'start_kernel' (and the early
 * #PF handler would create bootstrap pagetables) - so we are running
 * with the same assumptions as what to do when write_cr3 is executed
 * at this point.
 *
 * Since there are no user-page tables at all, we have two variants
 * of xen_write_cr3 - the early bootup (this one), and the late one
 * (xen_write_cr3). The reason we have to do that is that in 64-bit
 * the Linux kernel and user-space are both in ring 3 while the
 * hypervisor is in ring 0.
 */
static void __init xen_write_cr3_init(unsigned long cr3)
{
	BUG_ON(preemptible());

	xen_mc_batch();  /* disables interrupts */

	/* Update while interrupts are disabled, so its atomic with
	   respect to ipis */
	this_cpu_write(xen_cr3, cr3);

	__xen_write_cr3(true, cr3);

	xen_mc_issue(!xen_is_cpu_lazy_mode());  /* interrupts restored */
}

static int xen_pgd_alloc(struct mm_struct *mm)
{
	pgd_t *pgd = mm->pgd;
	struct page *page = virt_to_page(pgd);
	pgd_t *user_pgd;
	int ret = -ENOMEM;

	BUG_ON(PagePinned(virt_to_page(pgd)));
	BUG_ON(page->private != 0);

	user_pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
	page->private = (unsigned long)user_pgd;

	if (user_pgd != NULL) {
#ifdef CONFIG_X86_VSYSCALL_EMULATION
		user_pgd[pgd_index(VSYSCALL_ADDR)] =
			__pgd(__pa(level3_user_vsyscall) | _PAGE_TABLE);
#endif
		ret = 0;
	}

	BUG_ON(PagePinned(virt_to_page(xen_get_user_pgd(pgd))));

	return ret;
}

static void xen_pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
	pgd_t *user_pgd = xen_get_user_pgd(pgd);

	if (user_pgd)
		free_page((unsigned long)user_pgd);
}

/*
 * Init-time set_pte while constructing initial pagetables, which
 * doesn't allow RO page table pages to be remapped RW.
 *
 * If there is no MFN for this PFN then this page is initially
 * ballooned out so clear the PTE (as in decrease_reservation() in
 * drivers/xen/balloon.c).
 *
 * Many of these PTE updates are done on unpinned and writable pages
 * and doing a hypercall for these is unnecessary and expensive.  At
 * this point it is rarely possible to tell if a page is pinned, so
 * mostly write the PTE directly and rely on Xen trapping and
 * emulating any updates as necessary.
 */
static void __init xen_set_pte_init(pte_t *ptep, pte_t pte)
{
	if (unlikely(is_early_ioremap_ptep(ptep)))
		__xen_set_pte(ptep, pte);
	else
		native_set_pte(ptep, pte);
}

__visible pte_t xen_make_pte_init(pteval_t pte)
{
	unsigned long pfn;

	/*
	 * Pages belonging to the initial p2m list mapped outside the default

Annotation

Implementation Notes