svn commit: r235904 - in projects/amd64_xen_pv/sys: amd64/xen conf
Cherry G. Mathew
cherry at FreeBSD.org
Thu May 24 12:02:11 UTC 2012
Author: cherry
Date: Thu May 24 12:02:10 2012
New Revision: 235904
URL: http://svn.freebsd.org/changeset/base/235904
Log:
This API is an attempt to abstract the MMU state in an MI fashion. It is heavily wip and may or may not go away, from amd64/ depending on how things go with the direct mapped implementation
Added:
projects/amd64_xen_pv/sys/amd64/xen/mmu_map.c
projects/amd64_xen_pv/sys/amd64/xen/mmu_map.h
Modified:
projects/amd64_xen_pv/sys/conf/files.amd64
Added: projects/amd64_xen_pv/sys/amd64/xen/mmu_map.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/amd64_xen_pv/sys/amd64/xen/mmu_map.c Thu May 24 12:02:10 2012 (r235904)
@@ -0,0 +1,389 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2011-2012 Spectra Logic Corporation
+ * All rights reserved.
+ *
+ * This software was developed by Cherry G. Mathew <cherry at FreeBSD.org>
+ * under sponsorship from Spectra Logic Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+
+/*
+ * This file implements the API that manages the page table
+ * hierarchy for the amd64 Xen pmap.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_cpu.h"
+#include "opt_pmap.h"
+#include "opt_smp.h"
+
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
+#include <xen/hypervisor.h>
+#include <machine/xen/xenvar.h>
+
+#include <amd64/xen/mmu_map.h>
+
+static int
+pml4t_index(vm_offset_t va)
+{
+ /* amd64 sign extends 48th bit and upwards */
+ const uint64_t SIGNMASK = (1UL << 48) - 1;
+ va &= SIGNMASK; /* Remove sign extension */
+
+ return (va >> PML4SHIFT);
+}
+
+static int
+pdpt_index(vm_offset_t va)
+{
+ /* amd64 sign extends 48th bit and upwards */
+ const uint64_t SIGNMASK = (1UL << 48) - 1;
+ va &= SIGNMASK; /* Remove sign extension */
+
+ return ((va & PML4MASK) >> PDPSHIFT);
+}
+
+static int
+pdt_index(vm_offset_t va)
+{
+ /* amd64 sign extends 48th bit and upwards */
+ const uint64_t SIGNMASK = (1UL << 48) - 1;
+ va &= SIGNMASK; /* Remove sign extension */
+
+ return ((va & PDPMASK) >> PDRSHIFT);
+}
+
+/*
+ * The table get functions below assume that a table cannot exist at
+ * address 0
+ */
+static pml4_entry_t *
+pmap_get_pml4t(struct pmap *pm)
+{
+ KASSERT(pm != NULL,
+ ("NULL pmap passed in!\n"));
+
+ pml4_entry_t *pm_pml4 = pm->pm_pml4;
+
+ KASSERT(pm_pml4 != NULL,
+ ("pmap has NULL pml4!\n"));
+
+ return pm->pm_pml4;
+}
+
+/* Returns physical address */
+static vm_paddr_t
+pmap_get_pdpt(vm_offset_t va, pml4_entry_t *pml4t)
+{
+ pml4_entry_t pml4e;
+
+ KASSERT(va <= VM_MAX_KERNEL_ADDRESS,
+ ("invalid address requested"));
+ KASSERT(pml4t != 0, ("pml4t cannot be zero"));
+
+ pml4e = pml4t[pml4t_index(va)];
+
+ if (!(pml4e & PG_V)) {
+ return 0;
+ }
+
+ return xpmap_mtop(pml4e & PG_FRAME);
+}
+
+/* Returns physical address */
+static vm_paddr_t
+pmap_get_pdt(vm_offset_t va, pdp_entry_t *pdpt)
+{
+ pdp_entry_t pdpe;
+
+ KASSERT(va <= VM_MAX_KERNEL_ADDRESS,
+ ("invalid address requested"));
+ KASSERT(pdpt != 0, ("pdpt cannot be zero"));
+
+ pdpe = pdpt[pdpt_index(va)];
+
+ if (!(pdpe & PG_V)) {
+ return 0;
+ }
+
+ return xpmap_mtop(pdpe & PG_FRAME);
+}
+
+/* Returns physical address */
+static vm_paddr_t
+pmap_get_pt(vm_offset_t va, pd_entry_t *pdt)
+{
+ pd_entry_t pdte;
+
+ KASSERT(va <= VM_MAX_KERNEL_ADDRESS,
+ ("invalid address requested"));
+
+ KASSERT(pdt != 0, ("pdt cannot be zero"));
+
+ pdte = pdt[pdt_index(va)];
+
+ if (!(pdte & PG_V)) {
+ return 0;
+ }
+
+ return xpmap_mtop(pdte & PG_FRAME);
+}
+
+/*
+ * This structure defines the 4 indices that a given virtual
+ * address lookup would traverse.
+ *
+ * Note: this structure is opaque to API customers. Callers give us an
+ * untyped array which is marshalled/unmarshalled inside of the
+ * stateful api.
+ */
+
+static const uint64_t SANE = 0xcafebabe;
+
+struct mmu_map_index {
+ pml4_entry_t *pml4t; /* Page Map Level 4 Table */
+ pdp_entry_t *pdpt; /* Page Directory Pointer Table */
+ pd_entry_t *pdt; /* Page Directory Table */
+ pt_entry_t *pt; /* Page Table */
+
+ struct mmu_map_mbackend ptmb; /* Backend info */
+
+ uint32_t sanity; /* 32 bit (for alignment) magic XXX:
+ * Make optional on DEBUG */
+};
+
+size_t
+mmu_map_t_size(void)
+{
+ return sizeof (struct mmu_map_index);
+}
+
+void
+mmu_map_t_init(void *addr, struct mmu_map_mbackend *mb)
+{
+ KASSERT((addr != NULL) && (mb != NULL), ("NULL args given!"));
+ struct mmu_map_index *pti = addr;
+ KASSERT(pti->sanity != SANE, ("index initialised twice!"));
+ KASSERT(mb->alloc != NULL &&
+ mb->ptov != NULL &&
+ mb->vtop != NULL,
+ ("initialising with pre-registered alloc routine active"));
+
+ pti->ptmb = *mb;
+
+ /* Backend page allocation should provide default VA mapping */
+ pti->sanity = SANE;
+}
+
+void mmu_map_t_fini(void *addr)
+{
+ KASSERT(addr != NULL, ("NULL args given!"));
+
+ struct mmu_map_index *pti = addr;
+ KASSERT(pti->sanity == SANE, ("Uninitialised index cookie used"));
+ struct mmu_map_mbackend *mb = &pti->ptmb;
+
+ pti->sanity = 0;
+
+ if (mb->free != NULL) {
+ /* XXX: go through PT hierarchy and free + unmap
+ * unused tables */
+ }
+}
+
+pd_entry_t *
+mmu_map_pml4t(void *addr)
+{
+ KASSERT(addr != NULL, ("NULL args given!"));
+ struct mmu_map_index *pti = addr;
+
+ KASSERT(pti->sanity == SANE, ("Uninitialised index cookie used"));
+
+ return pti->pml4t;
+}
+
+pd_entry_t *
+mmu_map_pdpt(void *addr)
+{
+ KASSERT(addr != NULL, ("NULL args given!"));
+ struct mmu_map_index *pti = addr;
+
+ KASSERT(pti->sanity == SANE, ("Uninitialised index cookie used"));
+
+ return pti->pdpt;
+}
+
+pd_entry_t *
+mmu_map_pdt(void *addr)
+{
+ KASSERT(addr != NULL, ("NULL args given!"));
+ struct mmu_map_index *pti = addr;
+
+ KASSERT(pti->sanity == SANE, ("Uninitialised index cookie used"));
+
+ return pti->pdt;
+}
+
+pd_entry_t *
+mmu_map_pt(void *addr)
+{
+ KASSERT(addr != NULL, ("NULL args given!"));
+ struct mmu_map_index *pti = addr;
+
+ KASSERT(pti->sanity == SANE, ("Uninitialised index cookie used"));
+
+ return pti->pt;
+}
+
+bool
+mmu_map_inspect_va(struct pmap *pm, void *addr, vm_offset_t va)
+{
+ KASSERT(addr != NULL && pm != NULL, ("NULL arg(s) given"));
+
+ struct mmu_map_index *pti = addr;
+ KASSERT(pti->sanity == SANE, ("Uninitialised index cookie used"));
+
+ vm_paddr_t pt;
+
+ pti->pml4t = pmap_get_pml4t(pm);
+
+ pt = pmap_get_pdpt(va, pti->pml4t);
+
+ if (pt == 0) {
+ return false;
+ } else {
+ pti->pdpt = (pdp_entry_t *) pti->ptmb.ptov(pt);
+ }
+
+ pt = pmap_get_pdt(va, pti->pdpt);
+
+ if (pt == 0) {
+ return false;
+ } else {
+ pti->pdt = (pd_entry_t *) pti->ptmb.ptov(pt);
+ }
+
+ pt = pmap_get_pt(va, pti->pdt);
+
+ if (pt == 0) {
+ return false;
+ } else {
+ pti->pt = (pt_entry_t *)pti->ptmb.ptov(pt);
+ }
+
+ return true;
+}
+extern uint64_t xenstack; /* The stack Xen gives us at boot */
+void
+mmu_map_hold_va(struct pmap *pm, void *addr, vm_offset_t va)
+{
+ KASSERT(addr != NULL && pm != NULL, ("NULL arg(s) given"));
+
+ struct mmu_map_index *pti = addr;
+ KASSERT(pti->sanity == SANE, ("Uninitialised index cookie used"));
+
+ vm_paddr_t pt;
+
+ pti->pml4t = pmap_get_pml4t(pm);
+
+ pt = pmap_get_pdpt(va, pti->pml4t);
+
+ if (pt == 0) {
+ pml4_entry_t *pml4tep;
+ vm_paddr_t pml4tep_ma;
+ pml4_entry_t pml4te;
+
+ pti->pdpt = (pdp_entry_t *)pti->ptmb.alloc(PAGE_SIZE);
+
+ pml4tep = &pti->pml4t[pml4t_index(va)];
+ pml4tep_ma = xpmap_ptom(pti->ptmb.vtop((vm_offset_t)pml4tep));
+ pml4te = xpmap_ptom(pti->ptmb.vtop((vm_offset_t)pti->pdpt)) | PG_RW | PG_V | PG_U; /* XXX: revisit flags */
+ xen_queue_pt_update(pml4tep_ma, pml4te);
+
+ } else {
+ pti->pdpt = (pdp_entry_t *) pti->ptmb.ptov(pt);
+ }
+
+ pt = pmap_get_pdt(va, pti->pdpt);
+
+ if (pt == 0) {
+ pdp_entry_t *pdptep;
+ vm_paddr_t pdptep_ma;
+ pdp_entry_t pdpte;
+
+ pti->pdt = (pd_entry_t *)pti->ptmb.alloc(PAGE_SIZE);
+
+ pdptep = &pti->pdpt[pdpt_index(va)];
+ pdptep_ma = xpmap_ptom(pti->ptmb.vtop((vm_offset_t)pdptep));
+ pdpte = xpmap_ptom(pti->ptmb.vtop((vm_offset_t)pti->pdt)) | PG_RW | PG_V | PG_U; /* XXX: revisit flags */
+ xen_queue_pt_update(pdptep_ma, pdpte);
+
+ } else {
+ pti->pdt = (pd_entry_t *) pti->ptmb.ptov(pt);
+ }
+
+ pt = pmap_get_pt(va, pti->pdt);
+
+ if (pt == 0) {
+ pd_entry_t *pdtep;
+ vm_paddr_t pdtep_ma;
+ pd_entry_t pdte;
+
+ pti->pt = (pt_entry_t *) pti->ptmb.alloc(PAGE_SIZE);
+
+ pdtep = &pti->pdt[pdt_index(va)];
+ pdtep_ma = xpmap_ptom(pti->ptmb.vtop((vm_offset_t)pdtep));
+ pdte = xpmap_ptom(pti->ptmb.vtop((vm_offset_t)pti->pt)) | PG_RW | PG_V | PG_U; /* XXX: revisit flags */
+ xen_queue_pt_update(pdtep_ma, pdte);
+
+ } else {
+ pti->pt = (pt_entry_t *) pti->ptmb.ptov(pt);
+ }
+}
+
+void
+mmu_map_release_va(struct pmap *pm, void *addr, vm_offset_t va)
+{
+
+ KASSERT(addr != NULL && pm != NULL, ("NULL arg(s) given"));
+
+ struct mmu_map_index *pti = addr;
+ KASSERT(pti->sanity == SANE, ("Uninitialised index cookie used"));
+
+ /* XXX: */
+}
Added: projects/amd64_xen_pv/sys/amd64/xen/mmu_map.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/amd64_xen_pv/sys/amd64/xen/mmu_map.h Thu May 24 12:02:10 2012 (r235904)
@@ -0,0 +1,152 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2011-2012 Spectra Logic Corporation
+ * All rights reserved.
+ *
+ * This software was developed by Cherry G. Mathew <cherry at FreeBSD.org>
+ * under sponsorship from Spectra Logic Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#ifndef _XEN_MMU_MAP_H_
+#define _XEN_MMU_MAP_H_
+
+#include <sys/types.h>
+
+#include <machine/pmap.h>
+
+/*
+ *
+ * This API abstracts, in an MI fashion, the paging mechanism of an
+ * arbitrary CPU architecture as an opaque FSM, which may then be
+ * subject to inspection in MD ways.
+ *
+ * Use of this API can have the following effects on the VM system and
+ * the kernel address space:
+ *
+ * - physical memory pages may be allocated.
+ * - physical memory pages may be de-allocated.
+ * - kernel virtual address space may be allocated.
+ * - kernel virtual address space may be de-allocated.
+ * - The page table hierarchy may be modified.
+ * - TLB entries may be invalidated.
+ *
+ * The API is stateful, and designed around the following principles:
+ * - Simplicity
+ * - Object orientation
+ * - Code reuse.
+ */
+
+/*
+ * We hide the page table structure behind an opaque "index" cookie
+ * which acts as the "key" to a given va->pa mapping being inspected.
+ */
+typedef void * mmu_map_t;
+
+/*
+ * Memory backend types:
+ *
+ * We provide a means to allocate ad-hoc memory/physical page
+ * requirements to the paging mechanism by means of a "backend"
+ * alloc function
+ *
+ * The memory backend is required to provide physical pages that are
+ * at least temporarily mapped into the kernel VA space and whose
+ * contents are thus accessible by a simple pointer indirection from
+ * within the kernel. This requirement may be revoked after conclusion
+ * of an instance of stateful usage of the API ( See:
+ * mmu_map_t_fini() below ), at which point the backend
+ * implementation is free to unmap any temporary mappings if so
+ * desired. (XXX: review this for non-x86)
+ *
+ * Note: Only the mappings may be revoked - any physical pages
+ * themselves allocated by the backend are considered allocated and
+ * part of the paging mechanism.
+ */
+
+struct mmu_map_mbackend { /* Callbacks */
+
+ vm_offset_t (*alloc)(size_t);
+ void (*free)(vm_offset_t); /* May be NULL */
+
+ /*
+ * vtop()/ptov() conversion functions:
+ * These callbacks typically provide conversions for mapped
+ * pages allocated via the alloc()/free() callbacks (above).
+ * The API implementation is free to cache the mappings across
+ * multiple instances of use; ie; mappings may persist across
+ * one pair of mmu_map_t_init()/.._finit() calls.
+ */
+ vm_offset_t (*ptov)(vm_paddr_t);
+ vm_paddr_t (*vtop)(vm_offset_t);
+};
+
+/*
+ * Return sizeof (mmu_map_t) as implemented within the api
+ * This may then be used to allocate untyped memory for the cookie
+ * which can then be operated on opaquely behind the API in a machine
+ * specific manner.
+ */
+size_t mmu_map_t_size(void);
+
+/*
+ * Initialise the API state to use a specified memory backend
+ */
+void mmu_map_t_init(mmu_map_t, struct mmu_map_mbackend *);
+
+/* Conclude this instance of use of the API */
+void mmu_map_t_fini(mmu_map_t);
+
+/* Set "index" cookie state based on va lookup. This state may then be
+ * inspected in MD ways ( See below ). Note that every call to the
+ * following functions can change the state of the backing paging
+ * mechanism FSM.
+ */
+bool mmu_map_inspect_va(struct pmap *, mmu_map_t, vm_offset_t);
+/*
+ * Unconditionally allocate resources to setup and "inspect" (as
+ * above) a given va->pa mapping
+ */
+void mmu_map_hold_va(struct pmap *, mmu_map_t, vm_offset_t);
+
+/* Optionally release resources after tear down of a va->pa mapping */
+void mmu_map_release_va(struct pmap *, mmu_map_t, vm_offset_t);
+
+/*
+ * Machine dependant "view" into the page table hierarchy FSM.
+ * On amd64, there are four tables that are consulted for a va->pa
+ * translation. This information may be extracted by the MD functions
+ * below and is only considered valid between a successful call to
+ * mmu_map_inspect_va() or mmu_map_hold_va() and a subsequent
+ * call to mmu_map_release_va()
+ */
+pd_entry_t * mmu_map_pml4t(mmu_map_t); /* Page Map Level 4 Table */
+pd_entry_t * mmu_map_pdpt(mmu_map_t); /* Page Directory Pointer Table */
+pd_entry_t * mmu_map_pdt(mmu_map_t); /* Page Directory Table */
+pd_entry_t * mmu_map_pt(mmu_map_t); /* Page Table */
+
+#endif /* !_XEN_MMU_MAP_H_ */
Modified: projects/amd64_xen_pv/sys/conf/files.amd64
==============================================================================
--- projects/amd64_xen_pv/sys/conf/files.amd64 Thu May 24 11:52:57 2012 (r235903)
+++ projects/amd64_xen_pv/sys/conf/files.amd64 Thu May 24 12:02:10 2012 (r235904)
@@ -128,6 +128,7 @@ amd64/amd64/mpboot.S optional native sm
amd64/xen/mpboot.c optional xen smp
amd64/amd64/pmap.c optional native
amd64/xen/pmap.c optional xen
+amd64/xen/mmu_map.c optional xen
amd64/amd64/prof_machdep.c optional profiling-routine
amd64/amd64/ptrace_machdep.c standard
amd64/amd64/sigtramp.S standard
More information about the svn-src-projects
mailing list