#include <sys/types.h>
#include <sys/clock.h>
#include <sys/psm.h>
#include <sys/archsystm.h>
#include <sys/machsystm.h>
#include <sys/compress.h>
#include <sys/modctl.h>
#include <sys/trap.h>
#include <sys/panic.h>
#include <sys/regset.h>
#include <sys/frame.h>
#include <sys/kobj.h>
#include <sys/apic.h>
#include <sys/apic_timer.h>
#include <sys/dumphdr.h>
#include <sys/mem.h>
#include <sys/x86_archext.h>
#include <sys/xpv_panic.h>
#include <sys/boot_console.h>
#include <sys/bootsvcs.h>
#include <sys/consdev.h>
#include <vm/hat_pte.h>
#include <vm/hat_i86.h>
#define XPV_FILENAME "/boot/amd64/xen-syms"
#define XPV_MODNAME "xpv"
int xpv_panicking = 0;
struct module *xpv_module;
struct modctl *xpv_modctl;
#define ALIGN(x, a) ((a) == 0 ? (uintptr_t)(x) : \
(((uintptr_t)(x) + (uintptr_t)(a) - 1l) & ~((uintptr_t)(a) - 1l)))
static struct panic_info *xpv_panic_info = NULL;
#define NSEC_SHIFT 5
#define T_XPV_TIMER 0xd1
#define XPV_TIMER_INTERVAL 1000
static uint32_t *xpv_apicadr = NULL;
static uint_t nsec_scale;
#pragma align 16(xpv_panic_idt)
static gate_desc_t xpv_panic_idt[NIDT];
static pfn_t ptable_pfn[MAX_NUM_LEVEL];
static int xpv_dump_pages;
uintptr_t kpm1_low = 0;
uintptr_t kpm1_high = 0;
uintptr_t kpm2_low = 0;
uintptr_t kpm2_high = 0;
static int xpv_panic_nptes[MAX_NUM_LEVEL];
static ulong_t xpv_panic_cr3;
static uintptr_t xpv_end;
static void xpv_panic_console_print(const char *fmt, ...);
static void (*xpv_panic_printf)(const char *, ...) = xpv_panic_console_print;
#define CONSOLE_BUF_SIZE 256
static char console_buffer[CONSOLE_BUF_SIZE];
static boolean_t use_polledio;
xpv_mca_panic_data_t *xpv_mca_panic_data = NULL;
static void
xpv_panic_putc(int m)
{
struct cons_polledio *c = cons_polledio;
if (boot_console_type(NULL) == CONS_HYPERVISOR)
return;
if (use_polledio == B_TRUE)
c->cons_polledio_putchar(c->cons_polledio_argument, m);
else
bcons_putchar(m);
}
static void
xpv_panic_puts(char *msg)
{
char *m;
dump_timeleft = dump_timeout;
for (m = msg; *m; m++)
xpv_panic_putc((int)*m);
}
static void
xpv_panic_console_print(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
(void) vsnprintf(console_buffer, sizeof (console_buffer), fmt, ap);
va_end(ap);
xpv_panic_puts(console_buffer);
}
static void
xpv_panic_map(int level, pfn_t pfn)
{
x86pte_t pte, *pteptr;
pteptr = (x86pte_t *)PWIN_PTE_VA(level);
pte = pfn_to_pa(pfn) | PT_VALID;
XPV_ALLOW_PAGETABLE_UPDATES();
if (mmu.pae_hat)
*pteptr = pte;
else
*(x86pte32_t *)pteptr = pte;
XPV_DISALLOW_PAGETABLE_UPDATES();
mmu_flush_tlb_page((uintptr_t)PWIN_VA(level));
}
static pfn_t
xpv_va_walk(uintptr_t *vaddr)
{
int l, idx;
pfn_t pfn;
x86pte_t pte;
x86pte_t *ptep;
uintptr_t va = *vaddr;
uintptr_t scan_va;
caddr_t ptable_window;
static pfn_t toplevel_pfn;
static uintptr_t lastva;
pte = 0;
if (va != lastva + MMU_PAGESIZE)
for (l = mmu.max_level; l >= 0; l--)
ptable_pfn[l] = PFN_INVALID;
toplevel_pfn = mmu_btop(xpv_panic_cr3);
while (va < xpv_end && va >= *vaddr) {
pfn = toplevel_pfn;
for (l = mmu.max_level; l >= 0; l--) {
if (ptable_pfn[l] != pfn) {
xpv_panic_map(l, pfn);
ptable_pfn[l] = pfn;
}
ptable_window = PWIN_VA(l);
if (l == mmu.max_level && mmu.pae_hat)
ptable_window +=
(xpv_panic_cr3 & MMU_PAGEOFFSET);
idx = (va >> LEVEL_SHIFT(l)) & (xpv_panic_nptes[l] - 1);
scan_va = va;
while (idx < xpv_panic_nptes[l] && scan_va < xpv_end &&
scan_va >= *vaddr) {
ptep = (x86pte_t *)(ptable_window +
(idx << mmu.pte_size_shift));
pte = GET_PTE(ptep);
if (pte & PTE_VALID)
break;
idx++;
scan_va += mmu.level_size[l];
}
if (idx == xpv_panic_nptes[l]) {
va = NEXT_ENTRY_VA(va, l + 1);
break;
}
va = scan_va;
if (va >= xpv_end || va < *vaddr)
break;
pfn = PTE2MFN(pte, l);
if (!PTE_ISPAGE(pte, l))
continue;
if (((uintptr_t)xpv_apicadr & MMU_PAGEMASK) ==
(va & MMU_PAGEMASK)) {
va += MMU_PAGESIZE;
break;
}
if (va >= kpm1_low && va < kpm1_high) {
va = kpm1_high;
break;
}
if (va >= kpm2_low && va < kpm2_high) {
va = kpm2_high;
break;
}
if (l > 0) {
if (l > 1)
panic("Xen panic can't cope with "
"giant pages.");
idx = (va >> LEVEL_SHIFT(0)) &
(xpv_panic_nptes[0] - 1);
pfn += idx;
}
*vaddr = va;
lastva = va;
return (pfn | PFN_IS_FOREIGN_MFN);
}
}
return (PFN_INVALID);
}
int
dump_xpv_addr()
{
uintptr_t va;
mem_vtop_t mem_vtop;
xpv_dump_pages = 0;
va = xen_virt_start;
while (xpv_va_walk(&va) != PFN_INVALID) {
mem_vtop.m_as = &kas;
mem_vtop.m_va = (void *)va;
mem_vtop.m_pfn = (pfn_t)xpv_dump_pages | PFN_IS_FOREIGN_MFN;
dumpvp_write(&mem_vtop, sizeof (mem_vtop_t));
xpv_dump_pages++;
va += MMU_PAGESIZE;
}
mem_vtop.m_as = &kas;
mem_vtop.m_va = HYPERVISOR_shared_info;
mem_vtop.m_pfn = (pfn_t)xpv_dump_pages | PFN_IS_FOREIGN_MFN;
dumpvp_write(&mem_vtop, sizeof (mem_vtop_t));
xpv_dump_pages++;
return (xpv_dump_pages);
}
void
dump_xpv_pfn()
{
pfn_t pfn;
int cnt;
for (cnt = 0; cnt < xpv_dump_pages; cnt++) {
pfn = (pfn_t)cnt | PFN_IS_FOREIGN_MFN;
dumpvp_write(&pfn, sizeof (pfn));
}
}
int
dump_xpv_data(void *dump_cbuf)
{
uintptr_t va;
uint32_t csize;
int cnt = 0;
va = xen_virt_start;
while (xpv_va_walk(&va) != PFN_INVALID) {
csize = (uint32_t)compress((void *)va, dump_cbuf, PAGESIZE);
dumpvp_write(&csize, sizeof (uint32_t));
dumpvp_write(dump_cbuf, csize);
if (dump_ioerr) {
dumphdr->dump_flags &= ~DF_COMPLETE;
return (cnt);
}
cnt++;
va += MMU_PAGESIZE;
}
csize = (uint32_t)compress((void *)HYPERVISOR_shared_info, dump_cbuf,
PAGESIZE);
dumpvp_write(&csize, sizeof (uint32_t));
dumpvp_write(dump_cbuf, csize);
if (dump_ioerr)
dumphdr->dump_flags &= ~DF_COMPLETE;
cnt++;
return (cnt);
}
static void *
showstack(void *fpreg, int xpv_only)
{
struct frame *fpp;
ulong_t off;
char *sym;
uintptr_t pc, fp, lastfp;
uintptr_t minaddr = min(KERNELBASE, xen_virt_start);
fp = (uintptr_t)fpreg;
if (fp < minaddr) {
xpv_panic_printf("Bad frame ptr: 0x%p\n", fpreg);
return (fpreg);
}
do {
fpp = (struct frame *)fp;
pc = fpp->fr_savpc;
if ((xpv_only != 0) &&
(fp > xpv_end || fp < xen_virt_start))
break;
if ((sym = kobj_getsymname(pc, &off)) != NULL)
xpv_panic_printf("%08lx %s:%s+%lx\n", fp,
mod_containing_pc((caddr_t)pc), sym, off);
else if ((pc >= xen_virt_start) && (pc <= xpv_end))
xpv_panic_printf("%08lx 0x%lx (in Xen)\n", fp, pc);
else
xpv_panic_printf("%08lx %lx\n", fp, pc);
lastfp = fp;
fp = fpp->fr_savfp;
if (fp < lastfp) {
if ((~fp > minaddr) && ((~fp) ^ lastfp) < 0xfff)
fp = ~fp;
}
} while (fp > lastfp);
return ((void *)fp);
}
void *
xpv_traceback(void *fpreg)
{
return (showstack(fpreg, 1));
}
static void
xpv_panic_hypercall(ulong_t call)
{
panic("Illegally issued hypercall %d during panic!\n", (int)call);
}
void
xpv_die(struct regs *rp)
{
struct panic_trap_info ti;
struct cregs creg;
ti.trap_regs = rp;
ti.trap_type = rp->r_trapno;
curthread->t_panic_trap = &ti;
if (ti.trap_type == T_PGFLT) {
getcregs(&creg);
ti.trap_addr = (caddr_t)creg.cr_cr2;
panic("Fatal pagefault at 0x%lx. fault addr=0x%p rp=0x%p",
rp->r_pc, (void *)ti.trap_addr, (void *)rp);
} else {
ti.trap_addr = (caddr_t)rp->r_pc;
panic("Fatal trap %ld at 0x%lx. rp=0x%p", rp->r_trapno,
rp->r_pc, (void *)rp);
}
}
static void
switch_to_xpv_panic_idt()
{
int i;
desctbr_t idtr;
gate_desc_t *idt = xpv_panic_idt;
selector_t cs = get_cs_register();
for (i = 0; i < 32; i++)
set_gatesegd(&idt[i], &xpv_invaltrap, cs, SDT_SYSIGT, TRP_XPL,
0);
set_gatesegd(&idt[T_ZERODIV], &xpv_div0trap, cs, SDT_SYSIGT, TRP_XPL,
0);
set_gatesegd(&idt[T_SGLSTP], &xpv_dbgtrap, cs, SDT_SYSIGT, TRP_XPL, 0);
set_gatesegd(&idt[T_NMIFLT], &xpv_nmiint, cs, SDT_SYSIGT, TRP_XPL, 0);
set_gatesegd(&idt[T_BOUNDFLT], &xpv_boundstrap, cs, SDT_SYSIGT,
TRP_XPL, 0);
set_gatesegd(&idt[T_ILLINST], &xpv_invoptrap, cs, SDT_SYSIGT, TRP_XPL,
0);
set_gatesegd(&idt[T_NOEXTFLT], &xpv_ndptrap, cs, SDT_SYSIGT, TRP_XPL,
0);
set_gatesegd(&idt[T_TSSFLT], &xpv_invtsstrap, cs, SDT_SYSIGT, TRP_XPL,
0);
set_gatesegd(&idt[T_SEGFLT], &xpv_segnptrap, cs, SDT_SYSIGT, TRP_XPL,
0);
set_gatesegd(&idt[T_STKFLT], &xpv_stktrap, cs, SDT_SYSIGT, TRP_XPL, 0);
set_gatesegd(&idt[T_GPFLT], &xpv_gptrap, cs, SDT_SYSIGT, TRP_XPL, 0);
set_gatesegd(&idt[T_PGFLT], &xpv_pftrap, cs, SDT_SYSIGT, TRP_XPL, 0);
set_gatesegd(&idt[T_EXTERRFLT], &xpv_ndperr, cs, SDT_SYSIGT, TRP_XPL,
0);
set_gatesegd(&idt[T_ALIGNMENT], &xpv_achktrap, cs, SDT_SYSIGT, TRP_XPL,
0);
set_gatesegd(&idt[T_MCE], &xpv_mcetrap, cs, SDT_SYSIGT, TRP_XPL, 0);
set_gatesegd(&idt[T_SIMDFPE], &xpv_xmtrap, cs, SDT_SYSIGT, TRP_XPL, 0);
for (i = 33; i < NIDT; i++)
set_gatesegd(&idt[i], &xpv_surprise_intr, cs, SDT_SYSIGT,
TRP_XPL, 0);
set_gatesegd(&idt[T_XPV_TIMER], &xpv_timer_trap, cs, SDT_SYSIGT,
TRP_XPL, 0);
idtr.dtr_base = (uintptr_t)xpv_panic_idt;
idtr.dtr_limit = sizeof (xpv_panic_idt) - 1;
wr_idtr(&idtr);
wrmsr(MSR_AMD_LSTAR, (uintptr_t)xpv_panic_hypercall);
wrmsr(MSR_AMD_CSTAR, (uintptr_t)xpv_panic_hypercall);
}
static void
xpv_apic_clkinit()
{
uint_t apic_ticks = 0;
xpv_apicadr[APIC_SPUR_INT_REG] = AV_UNIT_ENABLE | APIC_SPUR_INTR;
xpv_apicadr[APIC_LOCAL_TIMER] = AV_MASK;
xpv_apicadr[APIC_INT_VECT0] = AV_MASK;
xpv_apicadr[APIC_DIVIDE_REG] = 0;
xpv_apicadr[APIC_INIT_COUNT] = APIC_MAXVAL;
drv_usecwait(XPV_TIMER_INTERVAL);
apic_ticks = APIC_MAXVAL - xpv_apicadr[APIC_CURR_COUNT];
xpv_apicadr[APIC_LOCAL_TIMER] = T_XPV_TIMER | AV_PERIODIC;
xpv_apicadr[APIC_INIT_COUNT] = apic_ticks;
xpv_apicadr[APIC_EOI_REG] = 0;
}
void
xpv_timer_tick(void)
{
static int ticks = 0;
if (ticks++ >= MICROSEC / XPV_TIMER_INTERVAL) {
ticks = 0;
if (dump_timeleft && (--dump_timeleft == 0))
panic("Xen panic timeout\n");
}
xpv_apicadr[APIC_EOI_REG] = 0;
}
void
xpv_interrupt(void)
{
#ifdef DEBUG
static int cnt = 0;
if (cnt++ < 10)
xpv_panic_printf("Unexpected interrupt received.\n");
if ((cnt < 1000) && ((cnt % 100) == 0))
xpv_panic_printf("%d unexpected interrupts received.\n", cnt);
#endif
xpv_apicadr[APIC_EOI_REG] = 0;
}
static hrtime_t
xpv_panic_gethrtime(void)
{
hrtime_t tsc, hrt;
unsigned int *l = (unsigned int *)&(tsc);
tsc = __rdtsc_insn();
hrt = (mul32(l[1], nsec_scale) << NSEC_SHIFT) +
(mul32(l[0], nsec_scale) >> (32 - NSEC_SHIFT));
return (hrt);
}
static void
xpv_panic_time_init()
{
nsec_scale =
CPU->cpu_m.mcpu_vcpu_info->time.tsc_to_system_mul >> NSEC_SHIFT;
gethrtimef = xpv_panic_gethrtime;
}
static void
xpv_panicsys(struct regs *rp, char *fmt, ...)
{
extern void panicsys(const char *, va_list, struct regs *, int);
va_list alist;
va_start(alist, fmt);
panicsys(fmt, alist, rp, 1);
va_end(alist);
}
void
xpv_do_panic(void *arg)
{
struct panic_info *pip = (struct panic_info *)arg;
int l;
struct cregs creg;
extern uintptr_t postbootkernelbase;
if (xpv_panicking++ > 0)
panic("multiple calls to xpv_do_panic()");
(void) panic_trigger(&panic_quiesce);
postbootkernelbase = xen_virt_start;
#if defined(HYPERVISOR_VIRT_END)
xpv_end = HYPERVISOR_VIRT_END;
#else
xpv_end = (uintptr_t)UINTPTR_MAX - sizeof (uintptr_t);
#endif
use_polledio = B_FALSE;
if (boot_console_type(NULL) == CONS_HYPERVISOR) {
bcons_device_change(CONS_HYPERVISOR);
} else if (cons_polledio != NULL &&
cons_polledio->cons_polledio_putchar != NULL) {
if (cons_polledio->cons_polledio_enter != NULL)
cons_polledio->cons_polledio_enter(
cons_polledio->cons_polledio_argument);
use_polledio = 1;
}
sysp->bsvc_putchar = xpv_panic_putc;
if (pip->pi_version != PANIC_INFO_VERSION)
xpv_panic_printf("Warning: Xen is using an unsupported "
"version of the panic_info structure.\n");
xpv_panic_info = pip;
kpm1_low = (uintptr_t)xpv_panic_info->pi_ram_start;
if (xpv_panic_info->pi_xen_start == NULL) {
kpm1_high = (uintptr_t)xpv_panic_info->pi_ram_end;
} else {
kpm1_high = (uintptr_t)xpv_panic_info->pi_xen_start;
kpm2_low = (uintptr_t)xpv_panic_info->pi_xen_end;
kpm2_high = (uintptr_t)xpv_panic_info->pi_ram_end;
}
xpv_panic_resetgs();
wrmsr(MSR_AMD_GSBASE, (uint64_t)&cpus[0]);
xpv_panic_time_init();
switch_to_xpv_panic_idt();
xpv_apicadr = pip->pi_apic;
xpv_apic_clkinit();
getcregs(&creg);
xpv_panic_cr3 = creg.cr_cr3;
for (l = mmu.max_level; l >= 0; l--)
xpv_panic_nptes[l] = mmu.ptes_per_table;
if (xpv_module != NULL) {
extern int last_module_id;
xpv_modctl->mod_id = last_module_id++;
xpv_modctl->mod_next = &modules;
xpv_modctl->mod_prev = modules.mod_prev;
modules.mod_prev->mod_next = xpv_modctl;
modules.mod_prev = xpv_modctl;
}
if (pip->pi_mca.mpd_magic == MCA_PANICDATA_MAGIC)
xpv_mca_panic_data = &pip->pi_mca;
xpv_panic_printf = printf;
xpv_panicsys((struct regs *)pip->pi_regs, pip->pi_panicstr);
xpv_panic_printf("Failed to reboot following panic.\n");
for (;;)
;
}
static void
init_xen_module()
{
struct _buf *file = NULL;
struct module *mp;
struct modctl *mcp;
int i, shn;
Shdr *shp, *ctf_shp;
char *names = NULL;
size_t n, namesize, text_align, data_align;
const char machine = EM_AMD64;
mp = kmem_zalloc(sizeof (*mp), KM_SLEEP);
mp->filename = kobj_zalloc(strlen(XPV_FILENAME) + 1, KM_SLEEP);
(void) strcpy(mp->filename, XPV_FILENAME);
mcp = kmem_zalloc(sizeof (*mcp), KM_SLEEP);
mcp->mod_modname = kobj_zalloc(strlen(XPV_MODNAME) + 1, KM_SLEEP);
(void) strcpy(mcp->mod_modname, XPV_MODNAME);
mcp->mod_filename = kobj_zalloc(strlen(XPV_FILENAME) + 1, KM_SLEEP);
(void) strcpy(mcp->mod_filename, XPV_FILENAME);
mcp->mod_inprogress_thread = (kthread_id_t)-1;
mcp->mod_ref = 1;
mcp->mod_loaded = 1;
mcp->mod_loadcnt = 1;
mcp->mod_mp = mp;
file = kobj_open_file(XPV_FILENAME);
if (file == (struct _buf *)-1) {
file = NULL;
goto err;
}
if (kobj_read_file(file, (char *)&mp->hdr, sizeof (mp->hdr), 0) < 0)
goto err;
for (i = 0; i < SELFMAG; i++)
if (mp->hdr.e_ident[i] != ELFMAG[i])
goto err;
if ((mp->hdr.e_ident[EI_DATA] != ELFDATA2LSB) ||
(mp->hdr.e_machine != machine))
goto err;
n = mp->hdr.e_shentsize * mp->hdr.e_shnum;
mp->shdrs = kmem_zalloc(n, KM_SLEEP);
if (kobj_read_file(file, mp->shdrs, n, mp->hdr.e_shoff) < 0)
goto err;
shp = (Shdr *)(mp->shdrs + mp->hdr.e_shstrndx * mp->hdr.e_shentsize);
namesize = shp->sh_size;
names = kmem_zalloc(shp->sh_size, KM_SLEEP);
if (kobj_read_file(file, names, shp->sh_size, shp->sh_offset) < 0)
goto err;
ctf_shp = NULL;
text_align = data_align = 0;
for (shn = 1; shn < mp->hdr.e_shnum; shn++) {
shp = (Shdr *)(mp->shdrs + shn * mp->hdr.e_shentsize);
if (shp->sh_name >= namesize)
continue;
if (shp->sh_type == SHT_SYMTAB) {
mp->symtbl_section = shn;
mp->symhdr = shp;
continue;
}
if ((shp->sh_size != 0) &&
(strcmp(names + shp->sh_name, ".SUNW_ctf") == 0)) {
ctf_shp = shp;
continue;
}
if (!(shp->sh_flags & SHF_ALLOC))
continue;
if ((strcmp(&names[shp->sh_name], ".text") != 0) &&
(shp->sh_flags & SHF_WRITE) != 0) {
if (shp->sh_addralign > data_align)
data_align = shp->sh_addralign;
mp->data_size = ALIGN(mp->data_size, data_align);
mp->data_size += ALIGN(shp->sh_size, 8);
if (mp->data == NULL || mp->data > (char *)shp->sh_addr)
mp->data = (char *)shp->sh_addr;
} else {
if (shp->sh_addralign > text_align)
text_align = shp->sh_addralign;
mp->text_size = ALIGN(mp->text_size, text_align);
mp->text_size += ALIGN(shp->sh_size, 8);
if (mp->text == NULL || mp->text > (char *)shp->sh_addr)
mp->text = (char *)shp->sh_addr;
}
}
kmem_free(names, namesize);
names = NULL;
shp = NULL;
mcp->mod_text = mp->text;
mcp->mod_text_size = mp->text_size;
if ((mp->symhdr != NULL) && (mp->symhdr->sh_link < mp->hdr.e_shnum)) {
mp->strhdr = (Shdr *)
(mp->shdrs + mp->symhdr->sh_link * mp->hdr.e_shentsize);
mp->nsyms = mp->symhdr->sh_size / mp->symhdr->sh_entsize;
mp->symsize = mp->symhdr->sh_size +
mp->nsyms * sizeof (symid_t) + mp->strhdr->sh_size;
mp->symspace = kmem_zalloc(mp->symsize, KM_SLEEP);
mp->symtbl = mp->symspace;
mp->strings = (char *)(mp->symtbl + mp->symhdr->sh_size);
if ((kobj_read_file(file, mp->symtbl,
mp->symhdr->sh_size, mp->symhdr->sh_offset) < 0) ||
(kobj_read_file(file, mp->strings,
mp->strhdr->sh_size, mp->strhdr->sh_offset) < 0))
goto err;
}
if ((ctf_shp != NULL) && ((moddebug & MODDEBUG_NOCTF) == 0)) {
mp->ctfdata = kmem_zalloc(ctf_shp->sh_size, KM_SLEEP);
mp->ctfsize = ctf_shp->sh_size;
if (kobj_read_file(file, mp->ctfdata, mp->ctfsize,
ctf_shp->sh_offset) < 0)
goto err;
}
kobj_close_file(file);
xpv_module = mp;
xpv_modctl = mcp;
return;
err:
cmn_err(CE_WARN, "Failed to initialize xpv module.");
if (file != NULL)
kobj_close_file(file);
kmem_free(mp->filename, strlen(XPV_FILENAME) + 1);
if (mp->shdrs != NULL)
kmem_free(mp->shdrs, mp->hdr.e_shentsize * mp->hdr.e_shnum);
if (mp->symspace != NULL)
kmem_free(mp->symspace, mp->symsize);
if (mp->ctfdata != NULL)
kmem_free(mp->ctfdata, mp->ctfsize);
kmem_free(mp, sizeof (*mp));
kmem_free(mcp->mod_filename, strlen(XPV_FILENAME) + 1);
kmem_free(mcp->mod_modname, strlen(XPV_MODNAME) + 1);
kmem_free(mcp, sizeof (*mcp));
if (names != NULL)
kmem_free(names, namesize);
}
void
xpv_panic_init()
{
xen_platform_op_t op;
int i;
ASSERT(DOMAIN_IS_INITDOMAIN(xen_info));
for (i = 0; i < mmu.num_level; i++)
ptable_pfn[i] = PFN_INVALID;
op.cmd = XENPF_panic_init;
op.interface_version = XENPF_INTERFACE_VERSION;
op.u.panic_init.panic_addr = (unsigned long)xpv_panic_hdlr;
(void) HYPERVISOR_platform_op(&op);
init_xen_module();
}