843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * CDDL HEADER START
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * The contents of this file are subject to the terms of the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Common Development and Distribution License (the "License").
843e19887f64dde75055cf8842fc4db2171eff45johnlev * You may not use this file except in compliance with the License.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
843e19887f64dde75055cf8842fc4db2171eff45johnlev * or http://www.opensolaris.org/os/licensing.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * See the License for the specific language governing permissions
843e19887f64dde75055cf8842fc4db2171eff45johnlev * and limitations under the License.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * When distributing Covered Code, include this CDDL HEADER in each
843e19887f64dde75055cf8842fc4db2171eff45johnlev * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * If applicable, add the following below this CDDL HEADER, with the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * fields enclosed by brackets "[]" replaced with your own identifying
843e19887f64dde75055cf8842fc4db2171eff45johnlev * information: Portions Copyright [yyyy] [name of copyright owner]
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * CDDL HEADER END
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
0d928757379972073af9fb22bdc827b74e8ba6acGary Mills * Copyright (c) 2012 Gary Mills
a9ba5504895c94d55fd9eb409fdb92f2385c9515Richard PALO * Copyright 2016 PALO, Richard.
0d928757379972073af9fb22bdc827b74e8ba6acGary Mills *
41afdfa77f9af46beb3aaab2eccc0d9afe660d31Krishnendu Sadhukhan - Sun Microsystems * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/types.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/clock.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/psm.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/archsystm.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/machsystm.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/compress.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/modctl.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/trap.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/panic.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/regset.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/frame.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/kobj.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/apic.h>
41afdfa77f9af46beb3aaab2eccc0d9afe660d31Krishnendu Sadhukhan - Sun Microsystems#include <sys/apic_timer.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/dumphdr.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/mem.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/x86_archext.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/xpv_panic.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/boot_console.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/bootsvcs.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/consdev.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <vm/hat_pte.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <vm/hat_i86.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* XXX: need to add a PAE version too, if we ever support both PAE and non */
843e19887f64dde75055cf8842fc4db2171eff45johnlev#if defined(__i386)
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define XPV_FILENAME "/boot/xen-syms"
843e19887f64dde75055cf8842fc4db2171eff45johnlev#else
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define XPV_FILENAME "/boot/amd64/xen-syms"
843e19887f64dde75055cf8842fc4db2171eff45johnlev#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define XPV_MODNAME "xpv"
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevint xpv_panicking = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstruct module *xpv_module;
843e19887f64dde75055cf8842fc4db2171eff45johnlevstruct modctl *xpv_modctl;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define ALIGN(x, a) ((a) == 0 ? (uintptr_t)(x) : \
843e19887f64dde75055cf8842fc4db2171eff45johnlev (((uintptr_t)(x) + (uintptr_t)(a) - 1l) & ~((uintptr_t)(a) - 1l)))
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* Pointer to the xpv_panic_info structure handed to us by Xen. */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic struct panic_info *xpv_panic_info = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* Timer support */
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define NSEC_SHIFT 5
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define T_XPV_TIMER 0xd1
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define XPV_TIMER_INTERVAL 1000 /* 1000 microseconds */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic uint32_t *xpv_apicadr = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic uint_t nsec_scale;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* IDT support */
843e19887f64dde75055cf8842fc4db2171eff45johnlev#pragma align 16(xpv_panic_idt)
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic gate_desc_t xpv_panic_idt[NIDT]; /* interrupt descriptor table */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* Xen pagetables mapped into our HAT's ptable windows */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic pfn_t ptable_pfn[MAX_NUM_LEVEL];
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* Number of MMU_PAGESIZE pages we're adding to the Solaris dump */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xpv_dump_pages;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab/*
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * There are up to two large swathes of RAM that we don't want to include
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * in the dump: those that comprise the Xen version of segkpm. On 32-bit
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * systems there is no such region of memory. On 64-bit systems, there
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * should be just a single contiguous region that corresponds to all of
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * physical memory. The tricky bit is that Xen's heap sometimes lives in
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * the middle of their segkpm, and is mapped using only kpm-like addresses.
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * In that case, we need to skip the swathes before and after Xen's heap.
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabuintptr_t kpm1_low = 0;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabuintptr_t kpm1_high = 0;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabuintptr_t kpm2_low = 0;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabuintptr_t kpm2_high = 0;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Some commonly used values that we don't want to recompute over and over.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int xpv_panic_nptes[MAX_NUM_LEVEL];
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic ulong_t xpv_panic_cr3;
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic uintptr_t xpv_end;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void xpv_panic_console_print(const char *fmt, ...);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void (*xpv_panic_printf)(const char *, ...) = xpv_panic_console_print;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define CONSOLE_BUF_SIZE 256
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic char console_buffer[CONSOLE_BUF_SIZE];
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic boolean_t use_polledio;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye/*
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * Pointers to machine check panic info (if any).
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye */
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Yexpv_mca_panic_data_t *xpv_mca_panic_data = NULL;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevxpv_panic_putc(int m)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct cons_polledio *c = cons_polledio;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* This really shouldn't happen */
0d928757379972073af9fb22bdc827b74e8ba6acGary Mills if (boot_console_type(NULL) == CONS_HYPERVISOR)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (use_polledio == B_TRUE)
843e19887f64dde75055cf8842fc4db2171eff45johnlev c->cons_polledio_putchar(c->cons_polledio_argument, m);
843e19887f64dde75055cf8842fc4db2171eff45johnlev else
843e19887f64dde75055cf8842fc4db2171eff45johnlev bcons_putchar(m);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevxpv_panic_puts(char *msg)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev char *m;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev dump_timeleft = dump_timeout;
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (m = msg; *m; m++)
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panic_putc((int)*m);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevxpv_panic_console_print(const char *fmt, ...)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev va_list ap;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev va_start(ap, fmt);
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) vsnprintf(console_buffer, sizeof (console_buffer), fmt, ap);
843e19887f64dde75055cf8842fc4db2171eff45johnlev va_end(ap);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panic_puts(console_buffer);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevxpv_panic_map(int level, pfn_t pfn)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev x86pte_t pte, *pteptr;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * The provided pfn represents a level 'level' page table. Map it
843e19887f64dde75055cf8842fc4db2171eff45johnlev * into the 'level' slot in the list of page table windows.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev pteptr = (x86pte_t *)PWIN_PTE_VA(level);
843e19887f64dde75055cf8842fc4db2171eff45johnlev pte = pfn_to_pa(pfn) | PT_VALID;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev XPV_ALLOW_PAGETABLE_UPDATES();
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (mmu.pae_hat)
843e19887f64dde75055cf8842fc4db2171eff45johnlev *pteptr = pte;
843e19887f64dde75055cf8842fc4db2171eff45johnlev else
843e19887f64dde75055cf8842fc4db2171eff45johnlev *(x86pte32_t *)pteptr = pte;
843e19887f64dde75055cf8842fc4db2171eff45johnlev XPV_DISALLOW_PAGETABLE_UPDATES();
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mmu_tlbflush_entry(PWIN_VA(level));
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Walk the page tables to find the pfn mapped by the given va.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic pfn_t
843e19887f64dde75055cf8842fc4db2171eff45johnlevxpv_va_walk(uintptr_t *vaddr)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int l, idx;
843e19887f64dde75055cf8842fc4db2171eff45johnlev pfn_t pfn;
843e19887f64dde75055cf8842fc4db2171eff45johnlev x86pte_t pte;
843e19887f64dde75055cf8842fc4db2171eff45johnlev x86pte_t *ptep;
843e19887f64dde75055cf8842fc4db2171eff45johnlev uintptr_t va = *vaddr;
843e19887f64dde75055cf8842fc4db2171eff45johnlev uintptr_t scan_va;
843e19887f64dde75055cf8842fc4db2171eff45johnlev caddr_t ptable_window;
843e19887f64dde75055cf8842fc4db2171eff45johnlev static pfn_t toplevel_pfn;
843e19887f64dde75055cf8842fc4db2171eff45johnlev static uintptr_t lastva;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * If we do anything other than a simple scan through memory, don't
843e19887f64dde75055cf8842fc4db2171eff45johnlev * trust the mapped page tables.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (va != lastva + MMU_PAGESIZE)
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (l = mmu.max_level; l >= 0; l--)
843e19887f64dde75055cf8842fc4db2171eff45johnlev ptable_pfn[l] = PFN_INVALID;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev toplevel_pfn = mmu_btop(xpv_panic_cr3);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev while (va < xpv_end && va >= *vaddr) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* Find the lowest table with any entry for va */
843e19887f64dde75055cf8842fc4db2171eff45johnlev pfn = toplevel_pfn;
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (l = mmu.max_level; l >= 0; l--) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ptable_pfn[l] != pfn) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panic_map(l, pfn);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ptable_pfn[l] = pfn;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Search this pagetable for any mapping to an
843e19887f64dde75055cf8842fc4db2171eff45johnlev * address >= va.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev ptable_window = PWIN_VA(l);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (l == mmu.max_level && mmu.pae_hat)
843e19887f64dde75055cf8842fc4db2171eff45johnlev ptable_window +=
843e19887f64dde75055cf8842fc4db2171eff45johnlev (xpv_panic_cr3 & MMU_PAGEOFFSET);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev idx = (va >> LEVEL_SHIFT(l)) & (xpv_panic_nptes[l] - 1);
843e19887f64dde75055cf8842fc4db2171eff45johnlev scan_va = va;
843e19887f64dde75055cf8842fc4db2171eff45johnlev while (idx < xpv_panic_nptes[l] && scan_va < xpv_end &&
843e19887f64dde75055cf8842fc4db2171eff45johnlev scan_va >= *vaddr) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev ptep = (x86pte_t *)(ptable_window +
843e19887f64dde75055cf8842fc4db2171eff45johnlev (idx << mmu.pte_size_shift));
843e19887f64dde75055cf8842fc4db2171eff45johnlev pte = GET_PTE(ptep);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (pte & PTE_VALID)
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev idx++;
843e19887f64dde75055cf8842fc4db2171eff45johnlev scan_va += mmu.level_size[l];
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * If there are no valid mappings in this table, we
843e19887f64dde75055cf8842fc4db2171eff45johnlev * can skip to the end of the VA range it covers.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (idx == xpv_panic_nptes[l]) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev va = NEXT_ENTRY_VA(va, l + 1);
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab va = scan_va;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab /*
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * See if we've hit the end of the range.
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (va >= xpv_end || va < *vaddr)
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab break;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * If this mapping is for a pagetable, we drop down
843e19887f64dde75055cf8842fc4db2171eff45johnlev * to the next level in the hierarchy and look for
843e19887f64dde75055cf8842fc4db2171eff45johnlev * a mapping in it.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev pfn = PTE2MFN(pte, l);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!PTE_ISPAGE(pte, l))
843e19887f64dde75055cf8842fc4db2171eff45johnlev continue;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * The APIC page is magic. Nothing to see here;
843e19887f64dde75055cf8842fc4db2171eff45johnlev * move along.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (((uintptr_t)xpv_apicadr & MMU_PAGEMASK) ==
843e19887f64dde75055cf8842fc4db2171eff45johnlev (va & MMU_PAGEMASK)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev va += MMU_PAGESIZE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab /*
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * See if the address is within one of the two
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * kpm-like regions we want to skip.
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (va >= kpm1_low && va < kpm1_high) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab va = kpm1_high;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab break;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (va >= kpm2_low && va < kpm2_high) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab va = kpm2_high;
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * The Xen panic code only handles small pages. If
843e19887f64dde75055cf8842fc4db2171eff45johnlev * this mapping is for a large page, we need to
843e19887f64dde75055cf8842fc4db2171eff45johnlev * identify the consituent page that covers the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * specific VA we were looking for.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (l > 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (l > 1)
843e19887f64dde75055cf8842fc4db2171eff45johnlev panic("Xen panic can't cope with "
843e19887f64dde75055cf8842fc4db2171eff45johnlev "giant pages.");
843e19887f64dde75055cf8842fc4db2171eff45johnlev idx = (va >> LEVEL_SHIFT(0)) &
843e19887f64dde75055cf8842fc4db2171eff45johnlev (xpv_panic_nptes[0] - 1);
843e19887f64dde75055cf8842fc4db2171eff45johnlev pfn += idx;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev *vaddr = va;
843e19887f64dde75055cf8842fc4db2171eff45johnlev lastva = va;
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (pfn | PFN_IS_FOREIGN_MFN);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (PFN_INVALID);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Walk through the Xen VA space, finding pages that are mapped in.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * These pages all have MFNs rather than PFNs, meaning they may be outside
843e19887f64dde75055cf8842fc4db2171eff45johnlev * the physical address space the kernel knows about, or they may collide
843e19887f64dde75055cf8842fc4db2171eff45johnlev * with PFNs the kernel is using.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * The obvious trick of just adding the PFN_IS_FOREIGN_MFN bit to the MFNs
843e19887f64dde75055cf8842fc4db2171eff45johnlev * to avoid collisions doesn't work. The pages need to be written to disk
843e19887f64dde75055cf8842fc4db2171eff45johnlev * in PFN-order or savecore gets confused. We can't allocate memory to
843e19887f64dde75055cf8842fc4db2171eff45johnlev * contruct a sorted pfn->VA reverse mapping, so we have to write the pages
843e19887f64dde75055cf8842fc4db2171eff45johnlev * to disk in VA order.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * To square this circle, we simply make up PFNs for each of Xen's pages.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * We assign each mapped page a fake PFN in ascending order. These fake
843e19887f64dde75055cf8842fc4db2171eff45johnlev * PFNs each have the FOREIGN bit set, ensuring that they fall outside the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * range of Solaris PFNs written by the kernel.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevint
843e19887f64dde75055cf8842fc4db2171eff45johnlevdump_xpv_addr()
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev uintptr_t va;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mem_vtop_t mem_vtop;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_dump_pages = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev va = xen_virt_start;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev while (xpv_va_walk(&va) != PFN_INVALID) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mem_vtop.m_as = &kas;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mem_vtop.m_va = (void *)va;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mem_vtop.m_pfn = (pfn_t)xpv_dump_pages | PFN_IS_FOREIGN_MFN;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev dumpvp_write(&mem_vtop, sizeof (mem_vtop_t));
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_dump_pages++;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev va += MMU_PAGESIZE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Add the shared_info page. This page actually ends up in the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * dump twice: once for the Xen va and once for the Solaris va.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * This isn't ideal, but we don't know the address Xen is using for
843e19887f64dde75055cf8842fc4db2171eff45johnlev * the page, so we can't share it.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev mem_vtop.m_as = &kas;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mem_vtop.m_va = HYPERVISOR_shared_info;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mem_vtop.m_pfn = (pfn_t)xpv_dump_pages | PFN_IS_FOREIGN_MFN;
843e19887f64dde75055cf8842fc4db2171eff45johnlev dumpvp_write(&mem_vtop, sizeof (mem_vtop_t));
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_dump_pages++;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (xpv_dump_pages);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevvoid
843e19887f64dde75055cf8842fc4db2171eff45johnlevdump_xpv_pfn()
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev pfn_t pfn;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int cnt;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (cnt = 0; cnt < xpv_dump_pages; cnt++) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev pfn = (pfn_t)cnt | PFN_IS_FOREIGN_MFN;
843e19887f64dde75055cf8842fc4db2171eff45johnlev dumpvp_write(&pfn, sizeof (pfn));
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevint
843e19887f64dde75055cf8842fc4db2171eff45johnlevdump_xpv_data(void *dump_cbuf)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev uintptr_t va;
843e19887f64dde75055cf8842fc4db2171eff45johnlev uint32_t csize;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int cnt = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * XXX: we should probably run this data through a UE check. The
843e19887f64dde75055cf8842fc4db2171eff45johnlev * catch is that the UE code relies on on_trap() and getpfnum()
843e19887f64dde75055cf8842fc4db2171eff45johnlev * working.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev va = xen_virt_start;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev while (xpv_va_walk(&va) != PFN_INVALID) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev csize = (uint32_t)compress((void *)va, dump_cbuf, PAGESIZE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev dumpvp_write(&csize, sizeof (uint32_t));
843e19887f64dde75055cf8842fc4db2171eff45johnlev dumpvp_write(dump_cbuf, csize);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (dump_ioerr) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev dumphdr->dump_flags &= ~DF_COMPLETE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (cnt);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev cnt++;
843e19887f64dde75055cf8842fc4db2171eff45johnlev va += MMU_PAGESIZE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Finally, dump the shared_info page
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev csize = (uint32_t)compress((void *)HYPERVISOR_shared_info, dump_cbuf,
843e19887f64dde75055cf8842fc4db2171eff45johnlev PAGESIZE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev dumpvp_write(&csize, sizeof (uint32_t));
843e19887f64dde75055cf8842fc4db2171eff45johnlev dumpvp_write(dump_cbuf, csize);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (dump_ioerr)
843e19887f64dde75055cf8842fc4db2171eff45johnlev dumphdr->dump_flags &= ~DF_COMPLETE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev cnt++;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (cnt);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void *
843e19887f64dde75055cf8842fc4db2171eff45johnlevshowstack(void *fpreg, int xpv_only)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct frame *fpp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ulong_t off;
843e19887f64dde75055cf8842fc4db2171eff45johnlev char *sym;
843e19887f64dde75055cf8842fc4db2171eff45johnlev uintptr_t pc, fp, lastfp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev uintptr_t minaddr = min(KERNELBASE, xen_virt_start);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev fp = (uintptr_t)fpreg;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (fp < minaddr) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panic_printf("Bad frame ptr: 0x%p\n", fpreg);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (fpreg);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev do {
843e19887f64dde75055cf8842fc4db2171eff45johnlev fpp = (struct frame *)fp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev pc = fpp->fr_savpc;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((xpv_only != 0) &&
843e19887f64dde75055cf8842fc4db2171eff45johnlev (fp > xpv_end || fp < xen_virt_start))
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((sym = kobj_getsymname(pc, &off)) != NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panic_printf("%08lx %s:%s+%lx\n", fp,
843e19887f64dde75055cf8842fc4db2171eff45johnlev mod_containing_pc((caddr_t)pc), sym, off);
843e19887f64dde75055cf8842fc4db2171eff45johnlev else if ((pc >= xen_virt_start) && (pc <= xpv_end))
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panic_printf("%08lx 0x%lx (in Xen)\n", fp, pc);
843e19887f64dde75055cf8842fc4db2171eff45johnlev else
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panic_printf("%08lx %lx\n", fp, pc);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev lastfp = fp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev fp = fpp->fr_savfp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Xen marks an exception frame by inverting the frame
843e19887f64dde75055cf8842fc4db2171eff45johnlev * pointer.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (fp < lastfp) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((~fp > minaddr) && ((~fp) ^ lastfp) < 0xfff)
843e19887f64dde75055cf8842fc4db2171eff45johnlev fp = ~fp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev } while (fp > lastfp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return ((void *)fp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevvoid *
843e19887f64dde75055cf8842fc4db2171eff45johnlevxpv_traceback(void *fpreg)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (showstack(fpreg, 1));
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#if defined(__amd64)
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevxpv_panic_hypercall(ulong_t call)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev panic("Illegally issued hypercall %d during panic!\n", (int)call);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevvoid
843e19887f64dde75055cf8842fc4db2171eff45johnlevxpv_die(struct regs *rp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct panic_trap_info ti;
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct cregs creg;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev ti.trap_regs = rp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ti.trap_type = rp->r_trapno;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev curthread->t_panic_trap = &ti;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ti.trap_type == T_PGFLT) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev getcregs(&creg);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ti.trap_addr = (caddr_t)creg.cr_cr2;
843e19887f64dde75055cf8842fc4db2171eff45johnlev panic("Fatal pagefault at 0x%lx. fault addr=0x%p rp=0x%p",
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh rp->r_pc, (void *)ti.trap_addr, (void *)rp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev ti.trap_addr = (caddr_t)rp->r_pc;
843e19887f64dde75055cf8842fc4db2171eff45johnlev panic("Fatal trap %ld at 0x%lx. rp=0x%p", rp->r_trapno,
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh rp->r_pc, (void *)rp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Build IDT to handle a Xen panic
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevswitch_to_xpv_panic_idt()
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev int i;
843e19887f64dde75055cf8842fc4db2171eff45johnlev desctbr_t idtr;
843e19887f64dde75055cf8842fc4db2171eff45johnlev gate_desc_t *idt = xpv_panic_idt;
843e19887f64dde75055cf8842fc4db2171eff45johnlev selector_t cs = get_cs_register();
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (i = 0; i < 32; i++)
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg set_gatesegd(&idt[i], &xpv_invaltrap, cs, SDT_SYSIGT, TRP_XPL,
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg 0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg set_gatesegd(&idt[T_ZERODIV], &xpv_div0trap, cs, SDT_SYSIGT, TRP_XPL,
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg 0);
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg set_gatesegd(&idt[T_SGLSTP], &xpv_dbgtrap, cs, SDT_SYSIGT, TRP_XPL, 0);
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg set_gatesegd(&idt[T_NMIFLT], &xpv_nmiint, cs, SDT_SYSIGT, TRP_XPL, 0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev set_gatesegd(&idt[T_BOUNDFLT], &xpv_boundstrap, cs, SDT_SYSIGT,
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg TRP_XPL, 0);
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg set_gatesegd(&idt[T_ILLINST], &xpv_invoptrap, cs, SDT_SYSIGT, TRP_XPL,
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg 0);
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg set_gatesegd(&idt[T_NOEXTFLT], &xpv_ndptrap, cs, SDT_SYSIGT, TRP_XPL,
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg 0);
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg set_gatesegd(&idt[T_TSSFLT], &xpv_invtsstrap, cs, SDT_SYSIGT, TRP_XPL,
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg 0);
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg set_gatesegd(&idt[T_SEGFLT], &xpv_segnptrap, cs, SDT_SYSIGT, TRP_XPL,
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg 0);
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg set_gatesegd(&idt[T_STKFLT], &xpv_stktrap, cs, SDT_SYSIGT, TRP_XPL, 0);
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg set_gatesegd(&idt[T_GPFLT], &xpv_gptrap, cs, SDT_SYSIGT, TRP_XPL, 0);
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg set_gatesegd(&idt[T_PGFLT], &xpv_pftrap, cs, SDT_SYSIGT, TRP_XPL, 0);
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg set_gatesegd(&idt[T_EXTERRFLT], &xpv_ndperr, cs, SDT_SYSIGT, TRP_XPL,
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg 0);
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg set_gatesegd(&idt[T_ALIGNMENT], &xpv_achktrap, cs, SDT_SYSIGT, TRP_XPL,
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg 0);
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg set_gatesegd(&idt[T_MCE], &xpv_mcetrap, cs, SDT_SYSIGT, TRP_XPL, 0);
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg set_gatesegd(&idt[T_SIMDFPE], &xpv_xmtrap, cs, SDT_SYSIGT, TRP_XPL, 0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * We have no double fault handler. Any single fault represents a
843e19887f64dde75055cf8842fc4db2171eff45johnlev * catastrophic failure for us, so there is no attempt to handle
843e19887f64dde75055cf8842fc4db2171eff45johnlev * them cleanly: we just print a message and reboot. If we
843e19887f64dde75055cf8842fc4db2171eff45johnlev * encounter a second fault while doing that, there is nothing
843e19887f64dde75055cf8842fc4db2171eff45johnlev * else we can do.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Be prepared to absorb any stray device interrupts received
843e19887f64dde75055cf8842fc4db2171eff45johnlev * while writing the core to disk.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (i = 33; i < NIDT; i++)
843e19887f64dde75055cf8842fc4db2171eff45johnlev set_gatesegd(&idt[i], &xpv_surprise_intr, cs, SDT_SYSIGT,
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg TRP_XPL, 0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* The one interrupt we expect to get is from the APIC timer. */
843e19887f64dde75055cf8842fc4db2171eff45johnlev set_gatesegd(&idt[T_XPV_TIMER], &xpv_timer_trap, cs, SDT_SYSIGT,
9844da31e6f9a1bffcbbb9ec7926f759ee04c460Seth Goldberg TRP_XPL, 0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev idtr.dtr_base = (uintptr_t)xpv_panic_idt;
843e19887f64dde75055cf8842fc4db2171eff45johnlev idtr.dtr_limit = sizeof (xpv_panic_idt) - 1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev wr_idtr(&idtr);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#if defined(__amd64)
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* Catch any hypercalls. */
843e19887f64dde75055cf8842fc4db2171eff45johnlev wrmsr(MSR_AMD_LSTAR, (uintptr_t)xpv_panic_hypercall);
843e19887f64dde75055cf8842fc4db2171eff45johnlev wrmsr(MSR_AMD_CSTAR, (uintptr_t)xpv_panic_hypercall);
843e19887f64dde75055cf8842fc4db2171eff45johnlev#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevxpv_apic_clkinit()
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev uint_t apic_ticks = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Measure how many APIC ticks there are within a fixed time
843e19887f64dde75055cf8842fc4db2171eff45johnlev * period. We're going to be fairly coarse here. This timer is
843e19887f64dde75055cf8842fc4db2171eff45johnlev * just being used to detect a stalled panic, so as long as we have
843e19887f64dde75055cf8842fc4db2171eff45johnlev * the right order of magnitude, everything should be fine.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_apicadr[APIC_SPUR_INT_REG] = AV_UNIT_ENABLE | APIC_SPUR_INTR;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_apicadr[APIC_LOCAL_TIMER] = AV_MASK;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_apicadr[APIC_INT_VECT0] = AV_MASK; /* local intr reg 0 */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_apicadr[APIC_DIVIDE_REG] = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_apicadr[APIC_INIT_COUNT] = APIC_MAXVAL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev drv_usecwait(XPV_TIMER_INTERVAL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev apic_ticks = APIC_MAXVAL - xpv_apicadr[APIC_CURR_COUNT];
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * apic_ticks now represents roughly how many apic ticks comprise
843e19887f64dde75055cf8842fc4db2171eff45johnlev * one timeout interval. Program the timer to send us an interrupt
843e19887f64dde75055cf8842fc4db2171eff45johnlev * every time that interval expires.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
41afdfa77f9af46beb3aaab2eccc0d9afe660d31Krishnendu Sadhukhan - Sun Microsystems xpv_apicadr[APIC_LOCAL_TIMER] = T_XPV_TIMER | AV_PERIODIC;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_apicadr[APIC_INIT_COUNT] = apic_ticks;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_apicadr[APIC_EOI_REG] = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevvoid
843e19887f64dde75055cf8842fc4db2171eff45johnlevxpv_timer_tick(void)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev static int ticks = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ticks++ >= MICROSEC / XPV_TIMER_INTERVAL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev ticks = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (dump_timeleft && (--dump_timeleft == 0))
843e19887f64dde75055cf8842fc4db2171eff45johnlev panic("Xen panic timeout\n");
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_apicadr[APIC_EOI_REG] = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevvoid
843e19887f64dde75055cf8842fc4db2171eff45johnlevxpv_interrupt(void)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev#ifdef DEBUG
843e19887f64dde75055cf8842fc4db2171eff45johnlev static int cnt = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (cnt++ < 10)
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panic_printf("Unexpected interrupt received.\n");
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((cnt < 1000) && ((cnt % 100) == 0))
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panic_printf("%d unexpected interrupts received.\n", cnt);
843e19887f64dde75055cf8842fc4db2171eff45johnlev#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_apicadr[APIC_EOI_REG] = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Managing time in panic context is trivial. We only have a single CPU,
843e19887f64dde75055cf8842fc4db2171eff45johnlev * we never get rescheduled, we never get suspended. We just need to
843e19887f64dde75055cf8842fc4db2171eff45johnlev * convert clock ticks into nanoseconds.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic hrtime_t
843e19887f64dde75055cf8842fc4db2171eff45johnlevxpv_panic_gethrtime(void)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev hrtime_t tsc, hrt;
843e19887f64dde75055cf8842fc4db2171eff45johnlev unsigned int *l = (unsigned int *)&(tsc);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev tsc = __rdtsc_insn();
843e19887f64dde75055cf8842fc4db2171eff45johnlev hrt = (mul32(l[1], nsec_scale) << NSEC_SHIFT) +
843e19887f64dde75055cf8842fc4db2171eff45johnlev (mul32(l[0], nsec_scale) >> (32 - NSEC_SHIFT));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (hrt);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevxpv_panic_time_init()
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev nsec_scale =
843e19887f64dde75055cf8842fc4db2171eff45johnlev CPU->cpu_m.mcpu_vcpu_info->time.tsc_to_system_mul >> NSEC_SHIFT;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev gethrtimef = xpv_panic_gethrtime;
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevxpv_panicsys(struct regs *rp, char *fmt, ...)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev extern void panicsys(const char *, va_list, struct regs *, int);
843e19887f64dde75055cf8842fc4db2171eff45johnlev va_list alist;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev va_start(alist, fmt);
843e19887f64dde75055cf8842fc4db2171eff45johnlev panicsys(fmt, alist, rp, 1);
843e19887f64dde75055cf8842fc4db2171eff45johnlev va_end(alist);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevvoid
843e19887f64dde75055cf8842fc4db2171eff45johnlevxpv_do_panic(void *arg)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct panic_info *pip = (struct panic_info *)arg;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int l;
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct cregs creg;
843e19887f64dde75055cf8842fc4db2171eff45johnlev#if defined(__amd64)
843e19887f64dde75055cf8842fc4db2171eff45johnlev extern uintptr_t postbootkernelbase;
843e19887f64dde75055cf8842fc4db2171eff45johnlev#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xpv_panicking++ > 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev panic("multiple calls to xpv_do_panic()");
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Indicate to the underlying panic framework that a panic has been
843e19887f64dde75055cf8842fc4db2171eff45johnlev * initiated. This is ordinarily done as part of vpanic(). Since
843e19887f64dde75055cf8842fc4db2171eff45johnlev * we already have all the register state saved by the hypervisor,
843e19887f64dde75055cf8842fc4db2171eff45johnlev * we skip that and jump straight into the panic processing code.
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye *
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * XXX If another thread grabs and wins the panic_quiesce trigger
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * then we'll have two threads in panicsys believing they are in
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye * charge of the panic attempt!
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) panic_trigger(&panic_quiesce);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#if defined(__amd64)
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * bzero() and bcopy() get unhappy when asked to operate on
843e19887f64dde75055cf8842fc4db2171eff45johnlev * addresses outside of the kernel. At this point Xen is really a
843e19887f64dde75055cf8842fc4db2171eff45johnlev * part of the kernel, so we update the routines' notion of where
843e19887f64dde75055cf8842fc4db2171eff45johnlev * the kernel starts.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev postbootkernelbase = xen_virt_start;
843e19887f64dde75055cf8842fc4db2171eff45johnlev#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#if defined(HYPERVISOR_VIRT_END)
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_end = HYPERVISOR_VIRT_END;
843e19887f64dde75055cf8842fc4db2171eff45johnlev#else
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_end = (uintptr_t)UINTPTR_MAX - sizeof (uintptr_t);
843e19887f64dde75055cf8842fc4db2171eff45johnlev#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * If we were redirecting console output to the hypervisor, we have
843e19887f64dde75055cf8842fc4db2171eff45johnlev * to stop.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev use_polledio = B_FALSE;
0d928757379972073af9fb22bdc827b74e8ba6acGary Mills if (boot_console_type(NULL) == CONS_HYPERVISOR) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev bcons_device_change(CONS_HYPERVISOR);
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else if (cons_polledio != NULL &&
843e19887f64dde75055cf8842fc4db2171eff45johnlev cons_polledio->cons_polledio_putchar != NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (cons_polledio->cons_polledio_enter != NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev cons_polledio->cons_polledio_enter(
843e19887f64dde75055cf8842fc4db2171eff45johnlev cons_polledio->cons_polledio_argument);
843e19887f64dde75055cf8842fc4db2171eff45johnlev use_polledio = 1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* Make sure we handle all console output from here on. */
843e19887f64dde75055cf8842fc4db2171eff45johnlev sysp->bsvc_putchar = xpv_panic_putc;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * If we find an unsupported panic_info structure, there's not much
843e19887f64dde75055cf8842fc4db2171eff45johnlev * we can do other than complain, plow on, and hope for the best.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (pip->pi_version != PANIC_INFO_VERSION)
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panic_printf("Warning: Xen is using an unsupported "
843e19887f64dde75055cf8842fc4db2171eff45johnlev "version of the panic_info structure.\n");
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panic_info = pip;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab#if defined(__amd64)
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab kpm1_low = (uintptr_t)xpv_panic_info->pi_ram_start;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (xpv_panic_info->pi_xen_start == NULL) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab kpm1_high = (uintptr_t)xpv_panic_info->pi_ram_end;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab } else {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab kpm1_high = (uintptr_t)xpv_panic_info->pi_xen_start;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab kpm2_low = (uintptr_t)xpv_panic_info->pi_xen_end;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab kpm2_high = (uintptr_t)xpv_panic_info->pi_ram_end;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab#endif
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Make sure we are running on the Solaris %gs. The Xen panic code
843e19887f64dde75055cf8842fc4db2171eff45johnlev * should already have set up the GDT properly.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panic_resetgs();
843e19887f64dde75055cf8842fc4db2171eff45johnlev#if defined(__amd64)
843e19887f64dde75055cf8842fc4db2171eff45johnlev wrmsr(MSR_AMD_GSBASE, (uint64_t)&cpus[0]);
843e19887f64dde75055cf8842fc4db2171eff45johnlev#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panic_time_init();
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Switch to our own IDT, avoiding any accidental returns to Xen
843e19887f64dde75055cf8842fc4db2171eff45johnlev * world.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev switch_to_xpv_panic_idt();
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Initialize the APIC timer, which is used to detect a hung dump
843e19887f64dde75055cf8842fc4db2171eff45johnlev * attempt.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_apicadr = pip->pi_apic;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_apic_clkinit();
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Set up a few values that we'll need repeatedly.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev getcregs(&creg);
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panic_cr3 = creg.cr_cr3;
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (l = mmu.max_level; l >= 0; l--)
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panic_nptes[l] = mmu.ptes_per_table;
843e19887f64dde75055cf8842fc4db2171eff45johnlev#ifdef __i386
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (mmu.pae_hat)
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panic_nptes[mmu.max_level] = 4;
843e19887f64dde75055cf8842fc4db2171eff45johnlev#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* Add the fake Xen module to the module list */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (xpv_module != NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev extern int last_module_id;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_modctl->mod_id = last_module_id++;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_modctl->mod_next = &modules;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_modctl->mod_prev = modules.mod_prev;
843e19887f64dde75055cf8842fc4db2171eff45johnlev modules.mod_prev->mod_next = xpv_modctl;
843e19887f64dde75055cf8842fc4db2171eff45johnlev modules.mod_prev = xpv_modctl;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye if (pip->pi_mca.mpd_magic == MCA_PANICDATA_MAGIC)
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye xpv_mca_panic_data = &pip->pi_mca;
e4b86885570d77af552e9cf94f142f4d744fb8c8Cheng Sean Ye
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panic_printf = printf;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panicsys((struct regs *)pip->pi_regs, pip->pi_panicstr);
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_panic_printf("Failed to reboot following panic.\n");
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (;;)
843e19887f64dde75055cf8842fc4db2171eff45johnlev ;
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Set up the necessary data structures to pretend that the Xen hypervisor
843e19887f64dde75055cf8842fc4db2171eff45johnlev * is a loadable module, allowing mdb to find the Xen symbols in a crash
843e19887f64dde75055cf8842fc4db2171eff45johnlev * dump. Since these symbols all map to VA space Solaris doesn't normally
843e19887f64dde75055cf8842fc4db2171eff45johnlev * have access to, we don't link these structures into the kernel's lists
843e19887f64dde75055cf8842fc4db2171eff45johnlev * until/unless we hit a Xen panic.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * The observant reader will note a striking amount of overlap between this
843e19887f64dde75055cf8842fc4db2171eff45johnlev * code and that found in krtld. While it would be handy if we could just
843e19887f64dde75055cf8842fc4db2171eff45johnlev * ask krtld to do this work for us, it's not that simple. Among the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * complications: we're not actually loading the text here (grub did it at
843e19887f64dde75055cf8842fc4db2171eff45johnlev * boot), the .text section is writable, there are no relocations to do,
843e19887f64dde75055cf8842fc4db2171eff45johnlev * none of the module text/data is in readable memory, etc. Training krtld
843e19887f64dde75055cf8842fc4db2171eff45johnlev * to deal with this weird module is as complicated, and more risky, than
843e19887f64dde75055cf8842fc4db2171eff45johnlev * reimplementing the necessary subset of it here.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevinit_xen_module()
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct _buf *file = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct module *mp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct modctl *mcp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int i, shn;
843e19887f64dde75055cf8842fc4db2171eff45johnlev Shdr *shp, *ctf_shp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev char *names = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev size_t n, namesize, text_align, data_align;
843e19887f64dde75055cf8842fc4db2171eff45johnlev#if defined(__amd64)
843e19887f64dde75055cf8842fc4db2171eff45johnlev const char machine = EM_AMD64;
843e19887f64dde75055cf8842fc4db2171eff45johnlev#else
843e19887f64dde75055cf8842fc4db2171eff45johnlev const char machine = EM_386;
843e19887f64dde75055cf8842fc4db2171eff45johnlev#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* Allocate and init the module structure */
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp = kmem_zalloc(sizeof (*mp), KM_SLEEP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->filename = kobj_zalloc(strlen(XPV_FILENAME) + 1, KM_SLEEP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) strcpy(mp->filename, XPV_FILENAME);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* Allocate and init the modctl structure */
843e19887f64dde75055cf8842fc4db2171eff45johnlev mcp = kmem_zalloc(sizeof (*mcp), KM_SLEEP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mcp->mod_modname = kobj_zalloc(strlen(XPV_MODNAME) + 1, KM_SLEEP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) strcpy(mcp->mod_modname, XPV_MODNAME);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mcp->mod_filename = kobj_zalloc(strlen(XPV_FILENAME) + 1, KM_SLEEP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) strcpy(mcp->mod_filename, XPV_FILENAME);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mcp->mod_inprogress_thread = (kthread_id_t)-1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mcp->mod_ref = 1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mcp->mod_loaded = 1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mcp->mod_loadcnt = 1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mcp->mod_mp = mp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Try to open a Xen image that hasn't had its symbol and CTF
843e19887f64dde75055cf8842fc4db2171eff45johnlev * information stripped off.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev file = kobj_open_file(XPV_FILENAME);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (file == (struct _buf *)-1) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev file = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto err;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Read the header and ensure that this is an ELF file for the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * proper ISA. If it's not, somebody has done something very
843e19887f64dde75055cf8842fc4db2171eff45johnlev * stupid. Why bother? See Mencken.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (kobj_read_file(file, (char *)&mp->hdr, sizeof (mp->hdr), 0) < 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto err;
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (i = 0; i < SELFMAG; i++)
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (mp->hdr.e_ident[i] != ELFMAG[i])
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto err;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((mp->hdr.e_ident[EI_DATA] != ELFDATA2LSB) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (mp->hdr.e_machine != machine))
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto err;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* Read in the section headers */
843e19887f64dde75055cf8842fc4db2171eff45johnlev n = mp->hdr.e_shentsize * mp->hdr.e_shnum;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->shdrs = kmem_zalloc(n, KM_SLEEP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (kobj_read_file(file, mp->shdrs, n, mp->hdr.e_shoff) < 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto err;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* Read the section names */
843e19887f64dde75055cf8842fc4db2171eff45johnlev shp = (Shdr *)(mp->shdrs + mp->hdr.e_shstrndx * mp->hdr.e_shentsize);
843e19887f64dde75055cf8842fc4db2171eff45johnlev namesize = shp->sh_size;
843e19887f64dde75055cf8842fc4db2171eff45johnlev names = kmem_zalloc(shp->sh_size, KM_SLEEP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (kobj_read_file(file, names, shp->sh_size, shp->sh_offset) < 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto err;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Fill in the text and data size fields.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev ctf_shp = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev text_align = data_align = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (shn = 1; shn < mp->hdr.e_shnum; shn++) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev shp = (Shdr *)(mp->shdrs + shn * mp->hdr.e_shentsize);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* Sanity check the offset of the section name */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (shp->sh_name >= namesize)
843e19887f64dde75055cf8842fc4db2171eff45johnlev continue;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* If we find the symtab section, remember it for later. */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (shp->sh_type == SHT_SYMTAB) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->symtbl_section = shn;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->symhdr = shp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev continue;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* If we find the CTF section, remember it for later. */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((shp->sh_size != 0) &&
843e19887f64dde75055cf8842fc4db2171eff45johnlev (strcmp(names + shp->sh_name, ".SUNW_ctf") == 0)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev ctf_shp = shp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev continue;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!(shp->sh_flags & SHF_ALLOC))
843e19887f64dde75055cf8842fc4db2171eff45johnlev continue;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Xen marks its text section as writable, so we need to
843e19887f64dde75055cf8842fc4db2171eff45johnlev * look for the name - not just the flag.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
a9ba5504895c94d55fd9eb409fdb92f2385c9515Richard PALO if ((strcmp(&names[shp->sh_name], ".text") != 0) &&
843e19887f64dde75055cf8842fc4db2171eff45johnlev (shp->sh_flags & SHF_WRITE) != 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (shp->sh_addralign > data_align)
843e19887f64dde75055cf8842fc4db2171eff45johnlev data_align = shp->sh_addralign;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->data_size = ALIGN(mp->data_size, data_align);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->data_size += ALIGN(shp->sh_size, 8);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (mp->data == NULL || mp->data > (char *)shp->sh_addr)
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->data = (char *)shp->sh_addr;
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (shp->sh_addralign > text_align)
843e19887f64dde75055cf8842fc4db2171eff45johnlev text_align = shp->sh_addralign;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->text_size = ALIGN(mp->text_size, text_align);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->text_size += ALIGN(shp->sh_size, 8);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (mp->text == NULL || mp->text > (char *)shp->sh_addr)
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->text = (char *)shp->sh_addr;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_free(names, namesize);
843e19887f64dde75055cf8842fc4db2171eff45johnlev names = NULL;
8cdfbd11336f55643933d1869e8c5a5c23dcd546nn shp = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mcp->mod_text = mp->text;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mcp->mod_text_size = mp->text_size;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * If we have symbol table and string table sections, read them in
843e19887f64dde75055cf8842fc4db2171eff45johnlev * now. If we don't, we just plow on. We'll still get a valid
843e19887f64dde75055cf8842fc4db2171eff45johnlev * core dump, but finding anything useful will be just a bit
843e19887f64dde75055cf8842fc4db2171eff45johnlev * harder.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Note: we don't bother with a hash table. We'll never do a
843e19887f64dde75055cf8842fc4db2171eff45johnlev * symbol lookup unless we crash, and then mdb creates its own. We
843e19887f64dde75055cf8842fc4db2171eff45johnlev * also don't try to perform any relocations. Xen should be loaded
843e19887f64dde75055cf8842fc4db2171eff45johnlev * exactly where the ELF file indicates, and the symbol information
843e19887f64dde75055cf8842fc4db2171eff45johnlev * in the file should be complete and correct already. Static
843e19887f64dde75055cf8842fc4db2171eff45johnlev * linking ain't all bad.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((mp->symhdr != NULL) && (mp->symhdr->sh_link < mp->hdr.e_shnum)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->strhdr = (Shdr *)
843e19887f64dde75055cf8842fc4db2171eff45johnlev (mp->shdrs + mp->symhdr->sh_link * mp->hdr.e_shentsize);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->nsyms = mp->symhdr->sh_size / mp->symhdr->sh_entsize;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* Allocate space for the symbol table and strings. */
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->symsize = mp->symhdr->sh_size +
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->nsyms * sizeof (symid_t) + mp->strhdr->sh_size;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->symspace = kmem_zalloc(mp->symsize, KM_SLEEP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->symtbl = mp->symspace;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->strings = (char *)(mp->symtbl + mp->symhdr->sh_size);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((kobj_read_file(file, mp->symtbl,
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->symhdr->sh_size, mp->symhdr->sh_offset) < 0) ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (kobj_read_file(file, mp->strings,
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->strhdr->sh_size, mp->strhdr->sh_offset) < 0))
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto err;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Read in the CTF section
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((ctf_shp != NULL) && ((moddebug & MODDEBUG_NOCTF) == 0)) {
8cdfbd11336f55643933d1869e8c5a5c23dcd546nn mp->ctfdata = kmem_zalloc(ctf_shp->sh_size, KM_SLEEP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mp->ctfsize = ctf_shp->sh_size;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (kobj_read_file(file, mp->ctfdata, mp->ctfsize,
843e19887f64dde75055cf8842fc4db2171eff45johnlev ctf_shp->sh_offset) < 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto err;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev kobj_close_file(file);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_module = mp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev xpv_modctl = mcp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev return;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnleverr:
843e19887f64dde75055cf8842fc4db2171eff45johnlev cmn_err(CE_WARN, "Failed to initialize xpv module.");
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (file != NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev kobj_close_file(file);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_free(mp->filename, strlen(XPV_FILENAME) + 1);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (mp->shdrs != NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_free(mp->shdrs, mp->hdr.e_shentsize * mp->hdr.e_shnum);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (mp->symspace != NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_free(mp->symspace, mp->symsize);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (mp->ctfdata != NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_free(mp->ctfdata, mp->ctfsize);
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_free(mp, sizeof (*mp));
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_free(mcp->mod_filename, strlen(XPV_FILENAME) + 1);
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_free(mcp->mod_modname, strlen(XPV_MODNAME) + 1);
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_free(mcp, sizeof (*mcp));
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (names != NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_free(names, namesize);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevvoid
843e19887f64dde75055cf8842fc4db2171eff45johnlevxpv_panic_init()
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev xen_platform_op_t op;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int i;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(DOMAIN_IS_INITDOMAIN(xen_info));
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (i = 0; i < mmu.num_level; i++)
843e19887f64dde75055cf8842fc4db2171eff45johnlev ptable_pfn[i] = PFN_INVALID;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* Let Xen know where to jump if/when it panics. */
843e19887f64dde75055cf8842fc4db2171eff45johnlev op.cmd = XENPF_panic_init;
843e19887f64dde75055cf8842fc4db2171eff45johnlev op.interface_version = XENPF_INTERFACE_VERSION;
843e19887f64dde75055cf8842fc4db2171eff45johnlev op.u.panic_init.panic_addr = (unsigned long)xpv_panic_hdlr;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) HYPERVISOR_platform_op(&op);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev init_xen_module();
843e19887f64dde75055cf8842fc4db2171eff45johnlev}