/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/archsystm.h>
#include <sys/bootconf.h>
#include <sys/bootsvcs.h>
#include <sys/bootinfo.h>
#include <sys/machparam.h>
#include <sys/machsystm.h>
#ifdef __xpv
#include <sys/hypervisor.h>
#endif
#include <vm/kboot_mmu.h>
#include <vm/seg_kmem.h>
#if 0
/*
* Joe's debug printing
*/
#define DBG(x) \
#else
#endif
/*
* Page table and memory stuff.
*/
/*
* this are needed by mmu_init()
*/
int kbm_largepage_support = 0;
/*
* Initialize memory management parameters for boot time page table management
*/
void
{
/*
* configure mmu information
*/
if (kbm_pae_support) {
ptes_per_table = 512;
pte_size = 8;
#ifdef __amd64
top_level = 3;
#else
top_level = 2;
#endif
} else {
ptes_per_table = 1024;
pte_size = 4;
top_level = 1;
}
#ifdef __xpv
#endif
}
/*
* Change the addressible page table window to point at a given page
*/
/*ARGSUSED*/
void *
{
#ifdef __xpv
if (!writeable)
pt_bits &= ~PT_WRITABLE;
bop_panic("HYPERVISOR_update_va_mapping() failed");
#else
if (kbm_pae_support)
else
#endif
return (window);
}
/*
* Add a mapping for the physical page at the given virtual address.
*/
void
{
if (khat_running)
panic("kbm_map() called too late");
if (level >= 1)
pteval |= PT_PAGESIZE;
if (kbm_pge_support && is_kernel)
#ifdef __xpv
/*
* try update_va_mapping first - fails if page table is missing.
*/
UVMF_INVLPG | UVMF_LOCAL) == 0)
return;
#endif
/*
* Find the pte that will map this address. This creates any
* missing intermediate level page tables.
*/
bop_panic("kbm_map: find_pte returned NULL");
#ifdef __xpv
bop_panic("HYPERVISOR_update_va_mapping() failed");
#else
if (kbm_pae_support)
else
#endif
}
#ifdef __xpv
/*
* Add a mapping for the machine page at the given virtual address.
*/
void
{
if (level == 1)
pteval |= PT_PAGESIZE;
/*
* try update_va_mapping first - fails if page table is missing.
*/
return;
/*
* Find the pte that will map this address. This creates any
* missing intermediate level page tables
*/
bop_panic("HYPERVISOR_update_va_mapping failed");
}
#endif /* __xpv */
/*
* Probe the boot time page tables to find the first mapping
* including va (or higher) and return non-zero if one is found.
* va is updated to the starting address and len to the pagesize.
* pp will be set to point to the 1st page_t of the mapped page(s).
*
* Note that if va is in the middle of a large page, the returned va
* will be less than what was asked for.
*/
int
{
level_t l;
if (khat_running)
panic("kbm_probe() called too late");
*len = 0;
*pfn = PFN_INVALID;
*prot = 0;
l = top_level;
for (;;) {
if (IN_VA_HOLE(probe_va))
if (IN_HYPERVISOR_VA(probe_va))
#else
return (0);
#endif
/*
* then we can bump VA by this level's pagesize and try again.
* When the probe_va wraps around, we are done.
*/
bop_panic("kbm_probe: find_pte returned NULL");
if (kbm_pae_support)
else
if (!PTE_ISVALID(pte_val)) {
return (0);
goto restart_new_va;
}
/*
* If this entry is a pointer to a lower level page table
* go down to it.
*/
if (!PTE_ISPAGE(pte_val, l)) {
ASSERT(l > 0);
--l;
continue;
}
/*
* We found a boot level page table entry
*/
*prot |= PROT_WRITE;
/*
* pt_nx is cleared if processor doesn't support NX bit
*/
return (1);
}
}
/*
* Destroy a boot loader page table 4K mapping.
*/
void
{
if (khat_running)
panic("kbm_unmap() called too late");
else {
#ifdef __xpv
(void) HYPERVISOR_update_va_mapping(va, 0,
#else
return;
if (kbm_pae_support)
*ptep = 0;
else
*((x86pte32_t *)ptep) = 0;
#endif
}
}
/*
* Change a boot loader page table 4K mapping.
* Returns the pfn of the old mapping.
*/
{
if (khat_running)
panic("kbm_remap() called too late");
bop_panic("kbm_remap: find_pte returned NULL");
if (kbm_pae_support)
else
#ifdef __xpv
bop_panic("HYPERVISOR_update_va_mapping() failed");
#else
if (kbm_pae_support)
else
#endif
return (PFN_INVALID);
}
/*
* Change a boot loader page table 4K mapping to read only.
*/
void
{
#ifdef __xpv
bop_panic("HYPERVISOR_update_va_mapping() failed");
#else
bop_panic("kbm_read_only: find_pte returned NULL");
if (kbm_pae_support)
else
#endif
}
/*
* interfaces for kernel debugger to access physical memory
*/
void *
{
if (first_time) {
first_time = 0;
return (window);
}
if (kbm_pae_support)
else
return (kbm_remap_window(pa, 0));
}
void
kbm_pop(void)
{
#ifdef __xpv
UVMF_INVLPG | UVMF_LOCAL) < 0)
bop_panic("HYPERVISOR_update_va_mapping() failed");
#else
if (kbm_pae_support)
else
#endif
}
{
if (kbm_pae_support)
}
#ifndef __xpv
void
{
if (kbm_pae_support)
else
reload_cr3();
}
#endif
{
void *table_ptr;
#ifdef __xpv
/* Remove write permission to the new page table. */
(void) kbm_remap_window(new_table, 0);
#endif
else
return (new_table);
}
x86pte_t *
{
}