/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/mach_mmu.h>
#include <sys/machsystm.h>
#include <sys/hypervisor.h>
#include <sys/bootconf.h>
#include <sys/sysmacros.h>
#include <vm/seg_kmem.h>
#include <vm/kboot_mmu.h>
/* that make up the pa_to_ma table */
/*
* We need to prevent migration or suspension of a domU while it's
* manipulating MFN values, as the MFN values will spontaneously
* change. The next 4 routines provide a mechanism for that.
* that is manipulating MFNs. Only the thread which is going to actually call
* HYPERVISOR_suspend() will become a writer.
*
* Since various places need to manipulate MFNs and also call the HAT,
* we track if a thread acquires reader status and allow it to recursively
* do so again. This prevents deadlocks if a migration request
* is started and waits for some reader, but then the previous reader needs
* to call into the HAT.
*/
static struct {
void
xen_block_migrate(void)
{
if (!DOMAIN_IS_INITDOMAIN(xen_info) &&
}
void
xen_allow_migrate(void)
{
if (!DOMAIN_IS_INITDOMAIN(xen_info) &&
}
void
xen_start_migrate(void)
{
int i;
for (i = 0; i < NUM_M2P_LOCKS; ++i)
}
void
xen_end_migrate(void)
{
int i;
for (i = 0; i < NUM_M2P_LOCKS; ++i)
}
/*ARGSUSED*/
void
{
mmu_update_t t;
int retcnt;
bop_panic("HYPERVISOR_mmu_update() failed");
}
/*
* The start_info_t and mfn_list are initially mapped in low "boot" memory.
* Each has a page aligned address and size. We relocate them up into the
* kernel's normal address space at this point in time. We also create
*/
void
xen_relocate_start_info(void)
{
int i, j;
/*
* In dom0, we have to account for the console_info structure
* which might immediately follow the start_info in memory.
*/
sz = sizeof (start_info_t);
if (DOMAIN_IS_INITDOMAIN(xen_info) &&
}
}
/*
* Relocate the mfn_list, any number of pages.
*/
0, 0, 0, VM_SLEEP);
}
/*
*/
if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
i = 0;
if (((j * sizeof (mfn_t)) & MMU_PAGEOFFSET) == 0) {
mfn_list_pages_page[i++] =
}
mfn_list_pages[j] =
}
}
/*
* Remap the shared info (for I/O) into high memory, too.
*/
sz = MMU_PAGESIZE;
/* shared info has no PFN so don't do: boot_mapin((caddr_t)addr, sz) */
HYPERVISOR_shared_info = (void *)addr;
/*
* Remap the console info into high memory, too.
*/
if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
sz = MMU_PAGESIZE;
HYPERVISOR_console_page = (void *)addr;
} else {
}
/*
* On domUs we need to have the xenbus page (store_mfn) mapped into
* the kernel. This is referenced as xb_addr.
*/
if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
}
}
/*
* Generate the pfn value to use for a foreign mfn.
*/
{
#ifdef DEBUG
/*
* make sure this MFN isn't in our list of MFNs
*/
if (on_trap_ready) {
panic("xen_assign_pfn() mfn belongs to us");
}
no_trap();
}
#endif /* DEBUG */
if (mfn == MFN_INVALID)
panic("xen_assign_pfn(MFN_INVALID) not allowed");
panic("xen_assign_pfn(mfn) PFN_IS_FOREIGN_MFN bit already set");
return (pfn);
}
void
{
if (pfn == PFN_INVALID)
panic("xen_release_pfn(PFN_INVALID) not allowed");
if ((pfn & PFN_IS_FOREIGN_MFN) == 0)
panic("mfn high bit not set");
}
{
if (pfn == PFN_INVALID)
return (0);
return ((pfn & PFN_IS_FOREIGN_MFN) != 0);
}
{
return (mfn_to_pfn(mfn));
}
{
if (pfn == PFN_INVALID)
panic("pfn_to_mfn(PFN_INVALID) not allowed");
if (pfn & PFN_IS_FOREIGN_MFN)
return (pfn & ~PFN_IS_FOREIGN_MFN);
}
/*
* This routine translates an MFN back into the corresponding PFN value.
* It has to be careful since the mfn_to_pfn_mapping[] might fault
* as that table is sparse. It also has to check for non-faulting, but out of
* range that exceed the table.
*/
{
/*
* Cleared at a suspend or migrate
*/
if (cached_max_mfn == 0)
if (cached_max_mfn < mfn)
} else {
}
if (on_trap_ready)
no_trap();
/*
* If khat_running is set then we should be checking
* in domUs that migration is blocked while using the
* mfn_to_pfn_mapping[] table.
*/
return (pfn);
}
/*
* From a pseudo-physical address, find the corresponding machine address.
*/
{
if (mfn == MFN_INVALID)
panic("pa_to_ma() got MFN_INVALID");
}
/*
* From a machine address, find the corresponding pseudo-physical address.
*/
{
if (pfn == PFN_INVALID)
panic("ma_to_pa() got PFN_INVALID");
}
/*
* When calling reassign_pfn(), the page must be (at least) read locked
* to make sure swrand does not try to grab it.
*/
#ifdef DEBUG
panic("reassign_pfn() called with unlocked page (pfn 0x%lx)", \
pfn); \
} \
}
#else /* DEBUG */
#endif /* DEBUG */
/*
* Reassign a new machine page to back a physical address.
*/
void
{
int mmu_update_return;
mmu_update_t t;
if (mfn == MFN_INVALID) {
panic("reassign_pfn(): failed to remove kpm mapping");
return;
}
/*
* Verify that previously given away pages are still page locked.
*/
}
panic("HYPERVISOR_mmu_update() failed");
panic("reassign_pfn(): failed to enable kpm mapping");
}