xref: /illumos-gate/usr/src/cmd/mdb/intel/modules/mdb_kb/mdb_kb.c (revision 349b53dd4e695e3d833b5380540385145b2d3ae8)
1843e1988Sjohnlev /*
2843e1988Sjohnlev  * CDDL HEADER START
3843e1988Sjohnlev  *
4843e1988Sjohnlev  * The contents of this file are subject to the terms of the
5843e1988Sjohnlev  * Common Development and Distribution License (the "License").
6843e1988Sjohnlev  * You may not use this file except in compliance with the License.
7843e1988Sjohnlev  *
8843e1988Sjohnlev  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9843e1988Sjohnlev  * or http://www.opensolaris.org/os/licensing.
10843e1988Sjohnlev  * See the License for the specific language governing permissions
11843e1988Sjohnlev  * and limitations under the License.
12843e1988Sjohnlev  *
13843e1988Sjohnlev  * When distributing Covered Code, include this CDDL HEADER in each
14843e1988Sjohnlev  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15843e1988Sjohnlev  * If applicable, add the following below this CDDL HEADER, with the
16843e1988Sjohnlev  * fields enclosed by brackets "[]" replaced with your own identifying
17843e1988Sjohnlev  * information: Portions Copyright [yyyy] [name of copyright owner]
18843e1988Sjohnlev  *
19843e1988Sjohnlev  * CDDL HEADER END
20843e1988Sjohnlev  */
21843e1988Sjohnlev /*
22*349b53ddSStuart Maybee  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23843e1988Sjohnlev  * Use is subject to license terms.
24843e1988Sjohnlev  */
25843e1988Sjohnlev 
26843e1988Sjohnlev /*
27a576ab5bSrab  * KVM backend for hypervisor domain dumps.  We don't use libkvm for
28a576ab5bSrab  * such dumps, since they do not have a namelist file or the typical
29a576ab5bSrab  * dump structures we expect to aid bootstrapping.  Instead, we
30a576ab5bSrab  * bootstrap based upon a debug_info structure at a known VA, using the
31a576ab5bSrab  * guest's own page tables to resolve to physical addresses, and
32a576ab5bSrab  * construct the namelist in a manner similar to ksyms_snapshot().
33a576ab5bSrab  *
34a576ab5bSrab  * Note that there are two formats understood by this module: the older,
35a576ab5bSrab  * ad hoc format, which we call 'core' within this file, and an
36a576ab5bSrab  * ELF-based format, known as 'elf'.
37a576ab5bSrab  *
38a576ab5bSrab  * We only support the older format generated on Solaris dom0: before we
39a576ab5bSrab  * fixed it, core dump files were broken whenever a PFN didn't map a
40a576ab5bSrab  * real MFN (!).
41843e1988Sjohnlev  */
42843e1988Sjohnlev 
43843e1988Sjohnlev #include <strings.h>
44843e1988Sjohnlev #include <stdio.h>
45843e1988Sjohnlev #include <stdlib.h>
46843e1988Sjohnlev #include <stddef.h>
47843e1988Sjohnlev #include <stdarg.h>
48843e1988Sjohnlev #include <unistd.h>
49843e1988Sjohnlev #include <fcntl.h>
50843e1988Sjohnlev #include <gelf.h>
51843e1988Sjohnlev #include <errno.h>
52843e1988Sjohnlev 
53843e1988Sjohnlev #include <sys/mman.h>
54843e1988Sjohnlev #include <sys/stat.h>
55843e1988Sjohnlev #include <sys/debug_info.h>
56843e1988Sjohnlev #include <sys/xen_mmu.h>
57843e1988Sjohnlev #include <sys/elf.h>
58843e1988Sjohnlev #include <sys/machelf.h>
59843e1988Sjohnlev #include <sys/modctl.h>
60843e1988Sjohnlev #include <sys/kobj.h>
61843e1988Sjohnlev #include <sys/kobj_impl.h>
62843e1988Sjohnlev #include <sys/sysmacros.h>
63843e1988Sjohnlev #include <sys/privmregs.h>
64843e1988Sjohnlev #include <vm/as.h>
65843e1988Sjohnlev 
66843e1988Sjohnlev #include <mdb/mdb_io.h>
67843e1988Sjohnlev #include <mdb/mdb_kb.h>
68843e1988Sjohnlev #include <mdb/mdb_target_impl.h>
69843e1988Sjohnlev 
70843e1988Sjohnlev #include <xen/public/xen.h>
71a576ab5bSrab #include <xen/public/version.h>
72a576ab5bSrab #include <xen/public/elfnote.h>
73843e1988Sjohnlev 
74843e1988Sjohnlev #define	XKB_SHDR_NULL 0
75843e1988Sjohnlev #define	XKB_SHDR_SYMTAB 1
76843e1988Sjohnlev #define	XKB_SHDR_STRTAB 2
77843e1988Sjohnlev #define	XKB_SHDR_SHSTRTAB 3
78843e1988Sjohnlev #define	XKB_SHDR_NUM 4
79843e1988Sjohnlev 
80843e1988Sjohnlev #define	XKB_WALK_LOCAL 0x1
81843e1988Sjohnlev #define	XKB_WALK_GLOBAL 0x2
82843e1988Sjohnlev #define	XKB_WALK_STR 0x4
83843e1988Sjohnlev #define	XKB_WALK_ALL (XKB_WALK_LOCAL | XKB_WALK_GLOBAL | XKB_WALK_STR)
84843e1988Sjohnlev 
85a576ab5bSrab #if defined(__i386)
86a576ab5bSrab #define	DEBUG_INFO 0xf4bff000
875d2eda97SJohn Levon #define	DEBUG_INFO_HVM 0xfe7ff000
88a576ab5bSrab #elif defined(__amd64)
89a576ab5bSrab #define	DEBUG_INFO 0xfffffffffb7ff000
905d2eda97SJohn Levon #define	DEBUG_INFO_HVM 0xfffffffffb7ff000
91a576ab5bSrab #endif
92a576ab5bSrab 
93843e1988Sjohnlev #define	PAGE_SIZE 0x1000
94843e1988Sjohnlev #define	PAGE_SHIFT 12
95843e1988Sjohnlev #define	PAGE_OFFSET(a) ((a) & (PAGE_SIZE - 1))
96843e1988Sjohnlev #define	PAGE_MASK(a) ((a) & ~(PAGE_SIZE - 1))
97a576ab5bSrab #define	PAGE_ALIGNED(a) (((a) & (PAGE_SIZE -1)) == 0)
985d2eda97SJohn Levon #define	PT_PADDR_LGPG 0x000fffffffffe000ull
99843e1988Sjohnlev #define	PT_PADDR 0x000ffffffffff000ull
100843e1988Sjohnlev #define	PT_VALID 0x1
1015d2eda97SJohn Levon #define	PT_PAGESIZE 0x080
1025d2eda97SJohn Levon #define	PTE_IS_LGPG(p, l) ((l) > 0 && ((p) & PT_PAGESIZE))
103843e1988Sjohnlev 
104843e1988Sjohnlev #define	XC_CORE_MAGIC 0xF00FEBED
105843e1988Sjohnlev #define	XC_CORE_MAGIC_HVM 0xF00FEBEE
106843e1988Sjohnlev 
107843e1988Sjohnlev #define	VGCF_HVM_GUEST (1<<1)
108843e1988Sjohnlev 
109843e1988Sjohnlev typedef struct xc_core_header {
110843e1988Sjohnlev 	unsigned int xch_magic;
111843e1988Sjohnlev 	unsigned int xch_nr_vcpus;
112843e1988Sjohnlev 	unsigned int xch_nr_pages;
113843e1988Sjohnlev 	unsigned int xch_ctxt_offset;
114843e1988Sjohnlev 	unsigned int xch_index_offset;
115843e1988Sjohnlev 	unsigned int xch_pages_offset;
116843e1988Sjohnlev } xc_core_header_t;
117843e1988Sjohnlev 
118a576ab5bSrab struct xc_elf_header {
119a576ab5bSrab 	uint64_t xeh_magic;
120a576ab5bSrab 	uint64_t xeh_nr_vcpus;
121a576ab5bSrab 	uint64_t xeh_nr_pages;
122a576ab5bSrab 	uint64_t xeh_page_size;
123a576ab5bSrab };
124a576ab5bSrab 
125a576ab5bSrab struct xc_elf_version {
126a576ab5bSrab 	uint64_t xev_major;
127a576ab5bSrab 	uint64_t xev_minor;
128a576ab5bSrab 	xen_extraversion_t xev_extra;
129a576ab5bSrab 	xen_compile_info_t xev_compile_info;
130a576ab5bSrab 	xen_capabilities_info_t xev_capabilities;
131a576ab5bSrab 	xen_changeset_info_t xev_changeset;
132a576ab5bSrab 	xen_platform_parameters_t xev_platform_parameters;
133a576ab5bSrab 	uint64_t xev_pagesize;
134a576ab5bSrab };
135a576ab5bSrab 
136a576ab5bSrab /*
137a576ab5bSrab  * Either an old-style (3.0.4) core format, or the ELF format.
138a576ab5bSrab  */
139a576ab5bSrab typedef enum {
140a576ab5bSrab 	XKB_FORMAT_UNKNOWN = 0,
141a576ab5bSrab 	XKB_FORMAT_CORE = 1,
142a576ab5bSrab 	XKB_FORMAT_ELF = 2
143a576ab5bSrab } xkb_type_t;
144a576ab5bSrab 
145843e1988Sjohnlev typedef struct mfn_map {
146843e1988Sjohnlev 	mfn_t mm_mfn;
147843e1988Sjohnlev 	char *mm_map;
148843e1988Sjohnlev } mfn_map_t;
149843e1988Sjohnlev 
150843e1988Sjohnlev typedef struct mmu_info {
151843e1988Sjohnlev 	size_t mi_max;
152843e1988Sjohnlev 	size_t mi_shift[4];
153843e1988Sjohnlev 	size_t mi_ptes;
154843e1988Sjohnlev 	size_t mi_ptesize;
155843e1988Sjohnlev } mmu_info_t;
156843e1988Sjohnlev 
157a576ab5bSrab typedef struct xkb_core {
158a576ab5bSrab 	xc_core_header_t xc_hdr;
159a576ab5bSrab 	void *xc_p2m_buf;
160a576ab5bSrab } xkb_core_t;
161a576ab5bSrab 
162a576ab5bSrab typedef struct xkb_elf {
163a576ab5bSrab 	mdb_gelf_file_t *xe_gelf;
164a576ab5bSrab 	size_t *xe_off;
165a576ab5bSrab 	struct xc_elf_header xe_hdr;
166a576ab5bSrab 	struct xc_elf_version xe_version;
167a576ab5bSrab } xkb_elf_t;
168a576ab5bSrab 
169843e1988Sjohnlev typedef struct xkb {
170843e1988Sjohnlev 	char *xkb_path;
171843e1988Sjohnlev 	int xkb_fd;
1725d2eda97SJohn Levon 	int xkb_is_hvm;
173a576ab5bSrab 
174a576ab5bSrab 	xkb_type_t xkb_type;
175a576ab5bSrab 	xkb_core_t xkb_core;
176a576ab5bSrab 	xkb_elf_t xkb_elf;
177a576ab5bSrab 
178a576ab5bSrab 	size_t xkb_nr_vcpus;
179a576ab5bSrab 	size_t xkb_nr_pages;
180a576ab5bSrab 	size_t xkb_pages_off;
181a576ab5bSrab 	xen_pfn_t xkb_max_pfn;
182843e1988Sjohnlev 	mfn_t xkb_max_mfn;
183a576ab5bSrab 	int xkb_is_pae;
184a576ab5bSrab 
185843e1988Sjohnlev 	mmu_info_t xkb_mmu;
186a576ab5bSrab 	debug_info_t xkb_info;
187a576ab5bSrab 
188*349b53ddSStuart Maybee 	void *xkb_vcpu_data;
189*349b53ddSStuart Maybee 	size_t xkb_vcpu_data_sz;
190*349b53ddSStuart Maybee 	struct vcpu_guest_context **xkb_vcpus;
191a576ab5bSrab 
192843e1988Sjohnlev 	char *xkb_pages;
193843e1988Sjohnlev 	mfn_t *xkb_p2m;
194843e1988Sjohnlev 	xen_pfn_t *xkb_m2p;
195843e1988Sjohnlev 	mfn_map_t xkb_pt_map[4];
196843e1988Sjohnlev 	mfn_map_t xkb_map;
197a576ab5bSrab 
198a576ab5bSrab 	char *xkb_namelist;
199a576ab5bSrab 	size_t xkb_namesize;
200843e1988Sjohnlev } xkb_t;
201843e1988Sjohnlev 
202843e1988Sjohnlev static const char xkb_shstrtab[] = "\0.symtab\0.strtab\0.shstrtab\0";
203843e1988Sjohnlev 
204843e1988Sjohnlev typedef struct xkb_namelist {
205843e1988Sjohnlev 	Ehdr	kh_elf_hdr;
206843e1988Sjohnlev 	Phdr	kh_text_phdr;
207843e1988Sjohnlev 	Phdr	kh_data_phdr;
208843e1988Sjohnlev 	Shdr	kh_shdr[XKB_SHDR_NUM];
209843e1988Sjohnlev 	char	shstrings[sizeof (xkb_shstrtab)];
210843e1988Sjohnlev } xkb_namelist_t;
211843e1988Sjohnlev 
212843e1988Sjohnlev static int xkb_build_ksyms(xkb_t *);
213843e1988Sjohnlev static offset_t xkb_mfn_to_offset(xkb_t *, mfn_t);
214843e1988Sjohnlev static mfn_t xkb_va_to_mfn(xkb_t *, uintptr_t, mfn_t);
215843e1988Sjohnlev static ssize_t xkb_read(xkb_t *, uintptr_t, void *, size_t);
216843e1988Sjohnlev static int xkb_read_word(xkb_t *, uintptr_t, uintptr_t *);
217843e1988Sjohnlev static char *xkb_map_mfn(xkb_t *, mfn_t, mfn_map_t *);
218843e1988Sjohnlev static int xkb_close(xkb_t *);
219843e1988Sjohnlev 
220a576ab5bSrab /*
221a576ab5bSrab  * Jump through the hoops we need to to correctly identify a core file
222a576ab5bSrab  * of either the old or new format.
223a576ab5bSrab  */
224843e1988Sjohnlev int
225843e1988Sjohnlev xkb_identify(const char *file, int *longmode)
226843e1988Sjohnlev {
227843e1988Sjohnlev 	xc_core_header_t header;
228a576ab5bSrab 	mdb_gelf_file_t *gf = NULL;
229a576ab5bSrab 	mdb_gelf_sect_t *sect = NULL;
230a576ab5bSrab 	mdb_io_t *io = NULL;
231a576ab5bSrab 	char *notes = NULL;
232a576ab5bSrab 	char *pos;
233a576ab5bSrab 	int ret = 0;
234843e1988Sjohnlev 	size_t sz;
235843e1988Sjohnlev 	int fd;
236843e1988Sjohnlev 
237843e1988Sjohnlev 	if ((fd = open64(file, O_RDONLY)) == -1)
238843e1988Sjohnlev 		return (-1);
239843e1988Sjohnlev 
240843e1988Sjohnlev 	if (pread64(fd, &header, sizeof (header), 0) != sizeof (header)) {
241843e1988Sjohnlev 		(void) close(fd);
242843e1988Sjohnlev 		return (0);
243843e1988Sjohnlev 	}
244843e1988Sjohnlev 
245843e1988Sjohnlev 	(void) close(fd);
246843e1988Sjohnlev 
247a576ab5bSrab 	if (header.xch_magic == XC_CORE_MAGIC) {
248a576ab5bSrab 		*longmode = 0;
249843e1988Sjohnlev 
250a576ab5bSrab 		/*
251a576ab5bSrab 		 * Indeed.
252a576ab5bSrab 		 */
253a576ab5bSrab 		sz = header.xch_index_offset - header.xch_ctxt_offset;
254843e1988Sjohnlev #ifdef _LP64
255a576ab5bSrab 		if (sizeof (struct vcpu_guest_context) *
256a576ab5bSrab 		    header.xch_nr_vcpus == sz)
257a576ab5bSrab 			*longmode = 1;
258843e1988Sjohnlev #else
259a576ab5bSrab 		if (sizeof (struct vcpu_guest_context) *
260a576ab5bSrab 		    header.xch_nr_vcpus != sz)
261a576ab5bSrab 			*longmode = 1;
262843e1988Sjohnlev #endif /* _LP64 */
263843e1988Sjohnlev 
264a576ab5bSrab 		return (1);
265a576ab5bSrab 	}
266a576ab5bSrab 
267a576ab5bSrab 	if ((io = mdb_fdio_create_path(NULL, file, O_RDONLY, 0)) == NULL)
268a576ab5bSrab 		return (-1);
269a576ab5bSrab 
270a576ab5bSrab 	if ((gf = mdb_gelf_create(io, ET_NONE, GF_FILE)) == NULL)
271a576ab5bSrab 		goto out;
272a576ab5bSrab 
273a576ab5bSrab 	if ((sect = mdb_gelf_sect_by_name(gf, ".note.Xen")) == NULL)
274a576ab5bSrab 		goto out;
275a576ab5bSrab 
276a576ab5bSrab 	if ((notes = mdb_gelf_sect_load(gf, sect)) == NULL)
277a576ab5bSrab 		goto out;
278a576ab5bSrab 
279a576ab5bSrab 	for (pos = notes; pos < notes + sect->gs_shdr.sh_size; ) {
280a576ab5bSrab 		struct xc_elf_version *vers;
281a576ab5bSrab 		/* LINTED - alignment */
282a576ab5bSrab 		Elf64_Nhdr *nhdr = (Elf64_Nhdr *)pos;
283a576ab5bSrab 		char *desc;
284a576ab5bSrab 		char *name;
285a576ab5bSrab 
286a576ab5bSrab 		name = pos + sizeof (*nhdr);
287a576ab5bSrab 		desc = (char *)P2ROUNDUP((uintptr_t)name + nhdr->n_namesz, 4);
288a576ab5bSrab 
289a576ab5bSrab 		pos = desc + nhdr->n_descsz;
290a576ab5bSrab 
291a576ab5bSrab 		if (nhdr->n_type != XEN_ELFNOTE_DUMPCORE_XEN_VERSION)
292a576ab5bSrab 			continue;
293a576ab5bSrab 
294a576ab5bSrab 		/*
295a576ab5bSrab 		 * The contents of this struct differ between 32 and 64
296a576ab5bSrab 		 * bit; however, not until past the 'xev_capabilities'
297a576ab5bSrab 		 * member, so we can just about get away with this.
298a576ab5bSrab 		 */
299a576ab5bSrab 
300a576ab5bSrab 		/* LINTED - alignment */
301a576ab5bSrab 		vers = (struct xc_elf_version *)desc;
302a576ab5bSrab 
303a576ab5bSrab 		if (strstr(vers->xev_capabilities, "x86_64")) {
304*349b53ddSStuart Maybee 			/*
305*349b53ddSStuart Maybee 			 * 64-bit hypervisor, but it can still be
306*349b53ddSStuart Maybee 			 * a 32-bit domain core. 32-bit domain cores
307*349b53ddSStuart Maybee 			 * are also dumped in Elf64 format, but they
308*349b53ddSStuart Maybee 			 * have e_machine set to EM_386, not EM_AMD64.
309*349b53ddSStuart Maybee 			 */
310*349b53ddSStuart Maybee 			if (gf->gf_ehdr.e_machine == EM_386)
311*349b53ddSStuart Maybee 				*longmode = 0;
312*349b53ddSStuart Maybee 			else
313*349b53ddSStuart Maybee 				*longmode = 1;
314a576ab5bSrab 		} else if (strstr(vers->xev_capabilities, "x86_32") ||
315a576ab5bSrab 		    strstr(vers->xev_capabilities, "x86_32p")) {
316*349b53ddSStuart Maybee 			/*
317*349b53ddSStuart Maybee 			 * 32-bit hypervisor, can only be a 32-bit core.
318*349b53ddSStuart Maybee 			 */
319a576ab5bSrab 			*longmode = 0;
320a576ab5bSrab 		} else {
321a576ab5bSrab 			mdb_warn("couldn't derive word size of dump; "
322a576ab5bSrab 			    "assuming 64-bit");
323a576ab5bSrab 			*longmode = 1;
324a576ab5bSrab 		}
325a576ab5bSrab 	}
326a576ab5bSrab 
327a576ab5bSrab 	ret = 1;
328a576ab5bSrab 
329a576ab5bSrab out:
330a576ab5bSrab 	if (gf != NULL)
331a576ab5bSrab 		mdb_gelf_destroy(gf);
332a576ab5bSrab 	else if (io != NULL)
333a576ab5bSrab 		mdb_io_destroy(io);
334a576ab5bSrab 	return (ret);
335843e1988Sjohnlev }
336843e1988Sjohnlev 
337843e1988Sjohnlev static void *
338843e1988Sjohnlev xkb_fail(xkb_t *xkb, const char *msg, ...)
339843e1988Sjohnlev {
340843e1988Sjohnlev 	va_list args;
341843e1988Sjohnlev 
342843e1988Sjohnlev 	va_start(args, msg);
343843e1988Sjohnlev 	if (xkb != NULL)
344843e1988Sjohnlev 		(void) fprintf(stderr, "%s: ", xkb->xkb_path);
345843e1988Sjohnlev 	(void) vfprintf(stderr, msg, args);
346843e1988Sjohnlev 	(void) fprintf(stderr, "\n");
347843e1988Sjohnlev 	va_end(args);
348843e1988Sjohnlev 	if (xkb != NULL)
349843e1988Sjohnlev 		(void) xkb_close(xkb);
350a576ab5bSrab 
351a576ab5bSrab 	errno = ENOEXEC;
352a576ab5bSrab 
353843e1988Sjohnlev 	return (NULL);
354843e1988Sjohnlev }
355843e1988Sjohnlev 
356843e1988Sjohnlev static int
357843e1988Sjohnlev xkb_build_m2p(xkb_t *xkb)
358843e1988Sjohnlev {
359843e1988Sjohnlev 	size_t i;
360843e1988Sjohnlev 
361a576ab5bSrab 	for (i = 0; i <= xkb->xkb_max_pfn; i++) {
362843e1988Sjohnlev 		if (xkb->xkb_p2m[i] != MFN_INVALID &&
363843e1988Sjohnlev 		    xkb->xkb_p2m[i] > xkb->xkb_max_mfn)
364843e1988Sjohnlev 			xkb->xkb_max_mfn = xkb->xkb_p2m[i];
365843e1988Sjohnlev 	}
366843e1988Sjohnlev 
367843e1988Sjohnlev 	xkb->xkb_m2p = mdb_alloc((xkb->xkb_max_mfn + 1) * sizeof (xen_pfn_t),
368843e1988Sjohnlev 	    UM_SLEEP);
369843e1988Sjohnlev 
370843e1988Sjohnlev 	for (i = 0; i <= xkb->xkb_max_mfn; i++)
371843e1988Sjohnlev 		xkb->xkb_m2p[i] = PFN_INVALID;
372843e1988Sjohnlev 
373a576ab5bSrab 	for (i = 0; i <= xkb->xkb_max_pfn; i++) {
374843e1988Sjohnlev 		if (xkb->xkb_p2m[i] != MFN_INVALID)
375843e1988Sjohnlev 			xkb->xkb_m2p[xkb->xkb_p2m[i]] = i;
376843e1988Sjohnlev 	}
377843e1988Sjohnlev 
378843e1988Sjohnlev 	return (1);
379843e1988Sjohnlev }
380843e1988Sjohnlev 
381843e1988Sjohnlev /*
382a576ab5bSrab  * With FORMAT_CORE, we can use the table in the dump file directly.
383a576ab5bSrab  * Just to make things fun, they've not page-aligned the p2m table.
384843e1988Sjohnlev  */
385843e1988Sjohnlev static int
386843e1988Sjohnlev xkb_map_p2m(xkb_t *xkb)
387843e1988Sjohnlev {
388843e1988Sjohnlev 	offset_t off;
389843e1988Sjohnlev 	size_t size;
390a576ab5bSrab 	xkb_core_t *xc = &xkb->xkb_core;
391a576ab5bSrab 	size_t count = xkb->xkb_nr_pages;
392a576ab5bSrab 	size_t boff = xc->xc_hdr.xch_index_offset;
393843e1988Sjohnlev 
394a576ab5bSrab 	size = (sizeof (mfn_t) * count) + (PAGE_SIZE * 2);
395843e1988Sjohnlev 	size = PAGE_MASK(size);
396843e1988Sjohnlev 	off = PAGE_MASK(boff);
397843e1988Sjohnlev 
398843e1988Sjohnlev 	/* LINTED - alignment */
399a576ab5bSrab 	xc->xc_p2m_buf = (mfn_t *)mmap(NULL, size, PROT_READ,
400843e1988Sjohnlev 	    MAP_SHARED, xkb->xkb_fd, off);
401843e1988Sjohnlev 
402a576ab5bSrab 	if (xc->xc_p2m_buf == (xen_pfn_t *)MAP_FAILED) {
403843e1988Sjohnlev 		(void) xkb_fail(xkb, "cannot map p2m table");
404843e1988Sjohnlev 		return (0);
405843e1988Sjohnlev 	}
406843e1988Sjohnlev 
407843e1988Sjohnlev 	/* LINTED - alignment */
408a576ab5bSrab 	xkb->xkb_p2m = (mfn_t *)((char *)xc->xc_p2m_buf +
409843e1988Sjohnlev 	    PAGE_OFFSET(boff));
410843e1988Sjohnlev 
411843e1988Sjohnlev 	return (1);
412843e1988Sjohnlev }
413843e1988Sjohnlev 
414a576ab5bSrab /*
415a576ab5bSrab  * With FORMAT_ELF, we have a set of <pfn,mfn> pairs, which we convert
416a576ab5bSrab  * into a linear array indexed by pfn for convenience.  We also need to
417a576ab5bSrab  * track the mapping between mfn and the offset in the file: a pfn with
418a576ab5bSrab  * no mfn will not appear in the core file.
419a576ab5bSrab  */
420a576ab5bSrab static int
421a576ab5bSrab xkb_build_p2m(xkb_t *xkb)
422a576ab5bSrab {
423a576ab5bSrab 	xkb_elf_t *xe = &xkb->xkb_elf;
424a576ab5bSrab 	mdb_gelf_sect_t *sect;
425a576ab5bSrab 	size_t size;
426a576ab5bSrab 	size_t i;
427a576ab5bSrab 
428a576ab5bSrab 	struct elf_p2m {
429a576ab5bSrab 		uint64_t pfn;
430a576ab5bSrab 		uint64_t gmfn;
431a576ab5bSrab 	} *p2m;
432a576ab5bSrab 
433a576ab5bSrab 	sect = mdb_gelf_sect_by_name(xe->xe_gelf, ".xen_p2m");
434a576ab5bSrab 
435a576ab5bSrab 	if (sect == NULL) {
436a576ab5bSrab 		(void) xkb_fail(xkb, "cannot find section .xen_p2m");
437a576ab5bSrab 		return (0);
438a576ab5bSrab 	}
439a576ab5bSrab 
440a576ab5bSrab 	if ((p2m = mdb_gelf_sect_load(xe->xe_gelf, sect)) == NULL) {
441a576ab5bSrab 		(void) xkb_fail(xkb, "couldn't read .xen_p2m");
442a576ab5bSrab 		return (0);
443a576ab5bSrab 	}
444a576ab5bSrab 
445a576ab5bSrab 	for (i = 0; i < xkb->xkb_nr_pages; i++) {
446a576ab5bSrab 		if (p2m[i].pfn > xkb->xkb_max_pfn)
447a576ab5bSrab 			xkb->xkb_max_pfn = p2m[i].pfn;
448a576ab5bSrab 	}
449a576ab5bSrab 
450a576ab5bSrab 	size = sizeof (xen_pfn_t) * (xkb->xkb_max_pfn + 1);
451a576ab5bSrab 	xkb->xkb_p2m = mdb_alloc(size, UM_SLEEP);
452a576ab5bSrab 	size = sizeof (size_t) * (xkb->xkb_max_pfn + 1);
453a576ab5bSrab 	xe->xe_off = mdb_alloc(size, UM_SLEEP);
454a576ab5bSrab 
455a576ab5bSrab 	for (i = 0; i <= xkb->xkb_max_pfn; i++) {
456a576ab5bSrab 		xkb->xkb_p2m[i] = PFN_INVALID;
457a576ab5bSrab 		xe->xe_off[i] = (size_t)-1;
458a576ab5bSrab 	}
459a576ab5bSrab 
460a576ab5bSrab 	for (i = 0; i < xkb->xkb_nr_pages; i++) {
461a576ab5bSrab 		xkb->xkb_p2m[p2m[i].pfn] = p2m[i].gmfn;
462a576ab5bSrab 		xe->xe_off[p2m[i].pfn] = i;
463a576ab5bSrab 	}
464a576ab5bSrab 
465a576ab5bSrab 	return (1);
466a576ab5bSrab }
467a576ab5bSrab 
4685d2eda97SJohn Levon /*
4695d2eda97SJohn Levon  * For HVM images, we don't have the corresponding MFN list; the table
4705d2eda97SJohn Levon  * is just a mapping from page index in the dump to the corresponding
4715d2eda97SJohn Levon  * PFN.  To simplify the other code, we'll pretend that these PFNs are
4725d2eda97SJohn Levon  * really MFNs as well, by populating xkb_p2m.
4735d2eda97SJohn Levon  */
4745d2eda97SJohn Levon static int
4755d2eda97SJohn Levon xkb_build_fake_p2m(xkb_t *xkb)
4765d2eda97SJohn Levon {
4775d2eda97SJohn Levon 	xkb_elf_t *xe = &xkb->xkb_elf;
4785d2eda97SJohn Levon 	mdb_gelf_sect_t *sect;
4795d2eda97SJohn Levon 	size_t size;
4805d2eda97SJohn Levon 	size_t i;
4815d2eda97SJohn Levon 
4825d2eda97SJohn Levon 	uint64_t *p2pfn;
4835d2eda97SJohn Levon 
4845d2eda97SJohn Levon 	sect = mdb_gelf_sect_by_name(xe->xe_gelf, ".xen_pfn");
4855d2eda97SJohn Levon 
4865d2eda97SJohn Levon 	if (sect == NULL) {
4875d2eda97SJohn Levon 		(void) xkb_fail(xkb, "cannot find section .xen_pfn");
4885d2eda97SJohn Levon 		return (0);
4895d2eda97SJohn Levon 	}
4905d2eda97SJohn Levon 
4915d2eda97SJohn Levon 	if ((p2pfn = mdb_gelf_sect_load(xe->xe_gelf, sect)) == NULL) {
4925d2eda97SJohn Levon 		(void) xkb_fail(xkb, "couldn't read .xen_pfn");
4935d2eda97SJohn Levon 		return (0);
4945d2eda97SJohn Levon 	}
4955d2eda97SJohn Levon 
4965d2eda97SJohn Levon 	for (i = 0; i < xkb->xkb_nr_pages; i++) {
497*349b53ddSStuart Maybee 		if (p2pfn[i] != PFN_INVALID && p2pfn[i] > xkb->xkb_max_pfn)
4985d2eda97SJohn Levon 			xkb->xkb_max_pfn = p2pfn[i];
4995d2eda97SJohn Levon 	}
5005d2eda97SJohn Levon 
5015d2eda97SJohn Levon 	size = sizeof (xen_pfn_t) * (xkb->xkb_max_pfn + 1);
5025d2eda97SJohn Levon 	xkb->xkb_p2m = mdb_alloc(size, UM_SLEEP);
503*349b53ddSStuart Maybee 
5045d2eda97SJohn Levon 	size = sizeof (size_t) * (xkb->xkb_max_pfn + 1);
5055d2eda97SJohn Levon 	xe->xe_off = mdb_alloc(size, UM_SLEEP);
5065d2eda97SJohn Levon 
5075d2eda97SJohn Levon 	for (i = 0; i <= xkb->xkb_max_pfn; i++) {
5085d2eda97SJohn Levon 		xkb->xkb_p2m[i] = PFN_INVALID;
5095d2eda97SJohn Levon 		xe->xe_off[i] = (size_t)-1;
5105d2eda97SJohn Levon 	}
5115d2eda97SJohn Levon 
5125d2eda97SJohn Levon 	for (i = 0; i < xkb->xkb_nr_pages; i++) {
513*349b53ddSStuart Maybee 		if (p2pfn[i] == PFN_INVALID)
514*349b53ddSStuart Maybee 			continue;
5155d2eda97SJohn Levon 		xkb->xkb_p2m[p2pfn[i]] = p2pfn[i];
5165d2eda97SJohn Levon 		xe->xe_off[p2pfn[i]] = i;
5175d2eda97SJohn Levon 	}
5185d2eda97SJohn Levon 
5195d2eda97SJohn Levon 	return (1);
5205d2eda97SJohn Levon }
5215d2eda97SJohn Levon 
522843e1988Sjohnlev /*
523843e1988Sjohnlev  * Return the MFN of the top-level page table for the given as.
524843e1988Sjohnlev  */
525843e1988Sjohnlev static mfn_t
526843e1988Sjohnlev xkb_as_to_mfn(xkb_t *xkb, struct as *as)
527843e1988Sjohnlev {
528843e1988Sjohnlev 	uintptr_t asp = (uintptr_t)as;
529843e1988Sjohnlev 	uintptr_t hatp;
530843e1988Sjohnlev 	uintptr_t htablep;
531843e1988Sjohnlev 	uintptr_t pfn;
532843e1988Sjohnlev 
533843e1988Sjohnlev 	if (!xkb_read_word(xkb, asp + offsetof(struct as, a_hat), &hatp))
534843e1988Sjohnlev 		return (MFN_INVALID);
535843e1988Sjohnlev 	if (!xkb_read_word(xkb, hatp + xkb->xkb_info.di_hat_htable_off,
536843e1988Sjohnlev 	    &htablep))
537843e1988Sjohnlev 		return (MFN_INVALID);
538843e1988Sjohnlev 	if (!xkb_read_word(xkb, htablep + xkb->xkb_info.di_ht_pfn_off,
539843e1988Sjohnlev 	    &pfn))
540843e1988Sjohnlev 		return (MFN_INVALID);
541843e1988Sjohnlev 
542a576ab5bSrab 	if (pfn > xkb->xkb_max_pfn)
543843e1988Sjohnlev 		return (MFN_INVALID);
544843e1988Sjohnlev 
545843e1988Sjohnlev 	return (xkb->xkb_p2m[pfn]);
546843e1988Sjohnlev }
547843e1988Sjohnlev 
5485d2eda97SJohn Levon static mfn_t
5495d2eda97SJohn Levon xkb_cr3_to_pfn(xkb_t *xkb)
5505d2eda97SJohn Levon {
551*349b53ddSStuart Maybee 	uint64_t cr3 = xkb->xkb_vcpus[0]->ctrlreg[3];
5525d2eda97SJohn Levon 	if (xkb->xkb_is_hvm)
5535d2eda97SJohn Levon 		return (cr3 >> PAGE_SHIFT);
5545d2eda97SJohn Levon 	return (xen_cr3_to_pfn(cr3));
5555d2eda97SJohn Levon }
5565d2eda97SJohn Levon 
557843e1988Sjohnlev static ssize_t
558843e1988Sjohnlev xkb_read_helper(xkb_t *xkb, struct as *as, int phys, uint64_t addr,
559843e1988Sjohnlev     void *buf, size_t size)
560843e1988Sjohnlev {
561843e1988Sjohnlev 	size_t left = size;
562a576ab5bSrab 	int windowed = (xkb->xkb_pages == NULL);
5635d2eda97SJohn Levon 	mfn_t tlmfn = xkb_cr3_to_pfn(xkb);
564843e1988Sjohnlev 
565843e1988Sjohnlev 	if (as != NULL && (tlmfn = xkb_as_to_mfn(xkb, as)) == MFN_INVALID)
566843e1988Sjohnlev 		return (-1);
567843e1988Sjohnlev 
568843e1988Sjohnlev 	while (left) {
569843e1988Sjohnlev 		uint64_t pos = addr + (size - left);
570843e1988Sjohnlev 		char *outpos = (char *)buf + (size - left);
571843e1988Sjohnlev 		size_t pageoff = PAGE_OFFSET(pos);
572843e1988Sjohnlev 		size_t sz = MIN(left, PAGE_SIZE - pageoff);
573843e1988Sjohnlev 		mfn_t mfn;
574843e1988Sjohnlev 
575843e1988Sjohnlev 		if (!phys) {
576843e1988Sjohnlev 			mfn = xkb_va_to_mfn(xkb, pos, tlmfn);
577843e1988Sjohnlev 			if (mfn == MFN_INVALID)
578843e1988Sjohnlev 				return (-1);
579843e1988Sjohnlev 		} else {
580843e1988Sjohnlev 			xen_pfn_t pfn = pos >> PAGE_SHIFT;
581a576ab5bSrab 			if (pfn > xkb->xkb_max_pfn)
582843e1988Sjohnlev 				return (-1);
583843e1988Sjohnlev 			mfn = xkb->xkb_p2m[pfn];
584843e1988Sjohnlev 			if (mfn == MFN_INVALID)
585843e1988Sjohnlev 				return (-1);
586843e1988Sjohnlev 		}
587843e1988Sjohnlev 
588843e1988Sjohnlev 		/*
589843e1988Sjohnlev 		 * If we're windowed then pread() is much faster.
590843e1988Sjohnlev 		 */
591843e1988Sjohnlev 		if (windowed) {
592843e1988Sjohnlev 			offset_t off = xkb_mfn_to_offset(xkb, mfn);
593843e1988Sjohnlev 			int ret;
594843e1988Sjohnlev 
595843e1988Sjohnlev 			if (off == ~1ULL)
596843e1988Sjohnlev 				return (-1);
597843e1988Sjohnlev 
598843e1988Sjohnlev 			off += pageoff;
599843e1988Sjohnlev 
600843e1988Sjohnlev 			ret = pread64(xkb->xkb_fd, outpos, sz, off);
601843e1988Sjohnlev 			if (ret == -1)
602843e1988Sjohnlev 				return (-1);
603843e1988Sjohnlev 			if (ret != sz)
604843e1988Sjohnlev 				return ((size - left) + ret);
605843e1988Sjohnlev 
606843e1988Sjohnlev 			left -= ret;
607843e1988Sjohnlev 		} else {
608843e1988Sjohnlev 			if (xkb_map_mfn(xkb, mfn, &xkb->xkb_map) == NULL)
609843e1988Sjohnlev 				return (-1);
610843e1988Sjohnlev 
611843e1988Sjohnlev 			bcopy(xkb->xkb_map.mm_map + pageoff, outpos, sz);
612843e1988Sjohnlev 
613843e1988Sjohnlev 			left -= sz;
614843e1988Sjohnlev 		}
615843e1988Sjohnlev 	}
616843e1988Sjohnlev 
617843e1988Sjohnlev 	return (size);
618843e1988Sjohnlev }
619843e1988Sjohnlev 
620843e1988Sjohnlev static ssize_t
621843e1988Sjohnlev xkb_pread(xkb_t *xkb, uint64_t addr, void *buf, size_t size)
622843e1988Sjohnlev {
623843e1988Sjohnlev 	return (xkb_read_helper(xkb, NULL, 1, addr, buf, size));
624843e1988Sjohnlev }
625843e1988Sjohnlev 
626843e1988Sjohnlev static ssize_t
627843e1988Sjohnlev xkb_aread(xkb_t *xkb, uintptr_t addr, void *buf, size_t size, struct as *as)
628843e1988Sjohnlev {
629843e1988Sjohnlev 	return (xkb_read_helper(xkb, as, 0, addr, buf, size));
630843e1988Sjohnlev }
631843e1988Sjohnlev 
632843e1988Sjohnlev static ssize_t
633843e1988Sjohnlev xkb_read(xkb_t *xkb, uintptr_t addr, void *buf, size_t size)
634843e1988Sjohnlev {
635843e1988Sjohnlev 	return (xkb_aread(xkb, addr, buf, size, NULL));
636843e1988Sjohnlev }
637843e1988Sjohnlev 
638843e1988Sjohnlev static int
639843e1988Sjohnlev xkb_read_word(xkb_t *xkb, uintptr_t addr, uintptr_t *buf)
640843e1988Sjohnlev {
641843e1988Sjohnlev 	if (xkb_read(xkb, addr, buf, sizeof (uintptr_t)) !=
642843e1988Sjohnlev 	    sizeof (uintptr_t))
643843e1988Sjohnlev 		return (0);
644843e1988Sjohnlev 	return (1);
645843e1988Sjohnlev }
646843e1988Sjohnlev 
647843e1988Sjohnlev static char *
648843e1988Sjohnlev xkb_readstr(xkb_t *xkb, uintptr_t addr)
649843e1988Sjohnlev {
650843e1988Sjohnlev 	char *str = mdb_alloc(1024, UM_SLEEP);
651843e1988Sjohnlev 	size_t i;
652843e1988Sjohnlev 
653843e1988Sjohnlev 	for (i = 0; i < 1024; i++) {
654843e1988Sjohnlev 		if (xkb_read(xkb, addr + i, &str[i], 1) != 1) {
655843e1988Sjohnlev 			mdb_free(str, 1024);
656843e1988Sjohnlev 			return (NULL);
657843e1988Sjohnlev 		}
658843e1988Sjohnlev 
659843e1988Sjohnlev 		if (str[i] == '\0')
660843e1988Sjohnlev 			break;
661843e1988Sjohnlev 	}
662843e1988Sjohnlev 
663843e1988Sjohnlev 	if (i == 1024) {
664843e1988Sjohnlev 		mdb_free(str, 1024);
665843e1988Sjohnlev 		return (NULL);
666843e1988Sjohnlev 	}
667843e1988Sjohnlev 
668843e1988Sjohnlev 	return (str);
669843e1988Sjohnlev }
670843e1988Sjohnlev 
671a576ab5bSrab static offset_t
672a576ab5bSrab xkb_pfn_to_off(xkb_t *xkb, xen_pfn_t pfn)
673a576ab5bSrab {
674a576ab5bSrab 	if (pfn == PFN_INVALID || pfn > xkb->xkb_max_pfn)
675a576ab5bSrab 		return (-1ULL);
676a576ab5bSrab 
677a576ab5bSrab 	if (xkb->xkb_type == XKB_FORMAT_CORE)
678a576ab5bSrab 		return (PAGE_SIZE * pfn);
679a576ab5bSrab 
680a576ab5bSrab 	return (PAGE_SIZE * (xkb->xkb_elf.xe_off[pfn]));
681a576ab5bSrab }
682a576ab5bSrab 
683843e1988Sjohnlev static offset_t
684843e1988Sjohnlev xkb_mfn_to_offset(xkb_t *xkb, mfn_t mfn)
685843e1988Sjohnlev {
686843e1988Sjohnlev 	xen_pfn_t pfn;
687843e1988Sjohnlev 
688843e1988Sjohnlev 	if (mfn > xkb->xkb_max_mfn)
689843e1988Sjohnlev 		return (-1ULL);
690843e1988Sjohnlev 
691843e1988Sjohnlev 	pfn = xkb->xkb_m2p[mfn];
692843e1988Sjohnlev 
693843e1988Sjohnlev 	if (pfn == PFN_INVALID)
694843e1988Sjohnlev 		return (-1ULL);
695843e1988Sjohnlev 
696a576ab5bSrab 	return (xkb->xkb_pages_off + xkb_pfn_to_off(xkb, pfn));
697843e1988Sjohnlev }
698843e1988Sjohnlev 
699843e1988Sjohnlev static char *
700843e1988Sjohnlev xkb_map_mfn(xkb_t *xkb, mfn_t mfn, mfn_map_t *mm)
701843e1988Sjohnlev {
702a576ab5bSrab 	int windowed = (xkb->xkb_pages == NULL);
703843e1988Sjohnlev 	offset_t off;
704843e1988Sjohnlev 
705843e1988Sjohnlev 	if (mm->mm_mfn == mfn)
706843e1988Sjohnlev 		return (mm->mm_map);
707843e1988Sjohnlev 
708843e1988Sjohnlev 	mm->mm_mfn = mfn;
709843e1988Sjohnlev 
710843e1988Sjohnlev 	if (windowed) {
711843e1988Sjohnlev 		if (mm->mm_map != (char *)MAP_FAILED) {
712843e1988Sjohnlev 			(void) munmap(mm->mm_map, PAGE_SIZE);
713843e1988Sjohnlev 			mm->mm_map = (void *)MAP_FAILED;
714843e1988Sjohnlev 		}
715843e1988Sjohnlev 
716843e1988Sjohnlev 		if ((off = xkb_mfn_to_offset(xkb, mfn)) == (-1ULL))
717843e1988Sjohnlev 			return (NULL);
718843e1988Sjohnlev 
719843e1988Sjohnlev 		mm->mm_map = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED,
720843e1988Sjohnlev 		    xkb->xkb_fd, off);
721843e1988Sjohnlev 
722843e1988Sjohnlev 		if (mm->mm_map == (char *)MAP_FAILED)
723843e1988Sjohnlev 			return (NULL);
724843e1988Sjohnlev 	} else {
725843e1988Sjohnlev 		xen_pfn_t pfn;
726843e1988Sjohnlev 
727843e1988Sjohnlev 		mm->mm_map = NULL;
728843e1988Sjohnlev 
729843e1988Sjohnlev 		if (mfn > xkb->xkb_max_mfn)
730843e1988Sjohnlev 			return (NULL);
731843e1988Sjohnlev 
732843e1988Sjohnlev 		pfn = xkb->xkb_m2p[mfn];
733843e1988Sjohnlev 
734843e1988Sjohnlev 		if (pfn == PFN_INVALID)
735843e1988Sjohnlev 			return (NULL);
736843e1988Sjohnlev 
737a576ab5bSrab 		mm->mm_map = xkb->xkb_pages + xkb_pfn_to_off(xkb, pfn);
738843e1988Sjohnlev 	}
739843e1988Sjohnlev 
740843e1988Sjohnlev 	return (mm->mm_map);
741843e1988Sjohnlev }
742843e1988Sjohnlev 
7435d2eda97SJohn Levon static uint64_t
7445d2eda97SJohn Levon xkb_get_pte(mmu_info_t *mmu, char *ptep)
745843e1988Sjohnlev {
746a576ab5bSrab 	uint64_t pte = 0;
747843e1988Sjohnlev 
748a576ab5bSrab 	if (mmu->mi_ptesize == 8) {
749a576ab5bSrab 		/* LINTED - alignment */
750a576ab5bSrab 		pte = *((uint64_t *)ptep);
751a576ab5bSrab 	} else {
752843e1988Sjohnlev 		/* LINTED - alignment */
753843e1988Sjohnlev 		pte = *((uint32_t *)ptep);
754843e1988Sjohnlev 	}
755843e1988Sjohnlev 
7565d2eda97SJohn Levon 	return (pte);
7575d2eda97SJohn Levon }
758843e1988Sjohnlev 
7595d2eda97SJohn Levon static mfn_t
7605d2eda97SJohn Levon xkb_pte_to_base_mfn(uint64_t pte, size_t level)
7615d2eda97SJohn Levon {
7625d2eda97SJohn Levon 	if (PTE_IS_LGPG(pte, level)) {
7635d2eda97SJohn Levon 		pte &= PT_PADDR_LGPG;
7645d2eda97SJohn Levon 	} else {
7655d2eda97SJohn Levon 		pte &= PT_PADDR;
7665d2eda97SJohn Levon 	}
767843e1988Sjohnlev 
768843e1988Sjohnlev 	return (pte >> PAGE_SHIFT);
769843e1988Sjohnlev }
770843e1988Sjohnlev 
771843e1988Sjohnlev /*
772843e1988Sjohnlev  * Resolve the given VA into an MFN, using the provided mfn as a top-level page
773843e1988Sjohnlev  * table.
774843e1988Sjohnlev  */
775843e1988Sjohnlev static mfn_t
776843e1988Sjohnlev xkb_va_to_mfn(xkb_t *xkb, uintptr_t va, mfn_t mfn)
777843e1988Sjohnlev {
778843e1988Sjohnlev 	mmu_info_t *mmu = &xkb->xkb_mmu;
7795d2eda97SJohn Levon 	uint64_t pte;
780843e1988Sjohnlev 	size_t level;
781843e1988Sjohnlev 
782843e1988Sjohnlev 	for (level = mmu->mi_max; ; --level) {
783843e1988Sjohnlev 		size_t entry;
784843e1988Sjohnlev 
785843e1988Sjohnlev 		if (xkb_map_mfn(xkb, mfn, &xkb->xkb_pt_map[level]) == NULL)
786843e1988Sjohnlev 			return (MFN_INVALID);
787843e1988Sjohnlev 
788843e1988Sjohnlev 		entry = (va >> mmu->mi_shift[level]) & (mmu->mi_ptes - 1);
789843e1988Sjohnlev 
7905d2eda97SJohn Levon 		pte = xkb_get_pte(mmu, (char *)xkb->xkb_pt_map[level].mm_map +
7915d2eda97SJohn Levon 		    entry * mmu->mi_ptesize);
792843e1988Sjohnlev 
7935d2eda97SJohn Levon 		if ((mfn = xkb_pte_to_base_mfn(pte, level)) == MFN_INVALID)
794843e1988Sjohnlev 			return (MFN_INVALID);
795843e1988Sjohnlev 
796843e1988Sjohnlev 		if (level == 0)
797843e1988Sjohnlev 			break;
7985d2eda97SJohn Levon 
7995d2eda97SJohn Levon 		/*
8005d2eda97SJohn Levon 		 * Currently 'mfn' refers to the base MFN of the
8015d2eda97SJohn Levon 		 * large-page mapping.  Add on the 4K-sized index into
8025d2eda97SJohn Levon 		 * the large-page mapping to get the right MFN within
8035d2eda97SJohn Levon 		 * the mapping.
8045d2eda97SJohn Levon 		 */
8055d2eda97SJohn Levon 		if (PTE_IS_LGPG(pte, level)) {
8065d2eda97SJohn Levon 			mfn += (va & ((1 << mmu->mi_shift[level]) - 1)) >>
8075d2eda97SJohn Levon 			    PAGE_SHIFT;
8085d2eda97SJohn Levon 			break;
8095d2eda97SJohn Levon 		}
810843e1988Sjohnlev 	}
811843e1988Sjohnlev 
812843e1988Sjohnlev 	return (mfn);
813843e1988Sjohnlev }
814843e1988Sjohnlev 
815843e1988Sjohnlev static int
816843e1988Sjohnlev xkb_read_module(xkb_t *xkb, uintptr_t modulep, struct module *module,
817843e1988Sjohnlev     uintptr_t *sym_addr, uintptr_t *sym_count, uintptr_t *str_addr)
818843e1988Sjohnlev {
819843e1988Sjohnlev 	if (xkb_read(xkb, modulep, module, sizeof (struct module)) !=
820843e1988Sjohnlev 	    sizeof (struct module))
821843e1988Sjohnlev 		return (0);
822843e1988Sjohnlev 
823843e1988Sjohnlev 	if (!xkb_read_word(xkb, (uintptr_t)module->symhdr +
824843e1988Sjohnlev 	    offsetof(Shdr, sh_addr), sym_addr))
825843e1988Sjohnlev 		return (0);
826843e1988Sjohnlev 
827843e1988Sjohnlev 	if (!xkb_read_word(xkb, (uintptr_t)module->strhdr +
828843e1988Sjohnlev 	    offsetof(Shdr, sh_addr), str_addr))
829843e1988Sjohnlev 		return (0);
830843e1988Sjohnlev 
831843e1988Sjohnlev 	if (!xkb_read_word(xkb, (uintptr_t)module->symhdr +
832843e1988Sjohnlev 	    offsetof(Shdr, sh_size), sym_count))
833843e1988Sjohnlev 		return (0);
834843e1988Sjohnlev 	*sym_count /= sizeof (Sym);
835843e1988Sjohnlev 
836843e1988Sjohnlev 	return (1);
837843e1988Sjohnlev }
838843e1988Sjohnlev 
839843e1988Sjohnlev static int
840843e1988Sjohnlev xkb_read_modsyms(xkb_t *xkb, char **buf, size_t *sizes, int types,
841843e1988Sjohnlev     uintptr_t sym_addr, uintptr_t str_addr, uintptr_t sym_count)
842843e1988Sjohnlev {
843843e1988Sjohnlev 	size_t i;
844843e1988Sjohnlev 
845843e1988Sjohnlev 	for (i = 0; i < sym_count; i++) {
846843e1988Sjohnlev 		Sym sym;
847843e1988Sjohnlev 		char *name;
848843e1988Sjohnlev 		size_t sz;
849843e1988Sjohnlev 		int type = XKB_WALK_GLOBAL;
850843e1988Sjohnlev 
851843e1988Sjohnlev 		if (xkb_read(xkb, sym_addr + i * sizeof (sym), &sym,
852843e1988Sjohnlev 		    sizeof (sym)) != sizeof (sym))
853843e1988Sjohnlev 			return (0);
854843e1988Sjohnlev 
855843e1988Sjohnlev 		if (GELF_ST_BIND(sym.st_info) == STB_LOCAL)
856843e1988Sjohnlev 			type = XKB_WALK_LOCAL;
857843e1988Sjohnlev 
858843e1988Sjohnlev 		name = xkb_readstr(xkb, str_addr + sym.st_name);
859843e1988Sjohnlev 
860843e1988Sjohnlev 		sym.st_shndx = SHN_ABS;
861843e1988Sjohnlev 		sym.st_name = sizes[XKB_WALK_STR];
862843e1988Sjohnlev 
863843e1988Sjohnlev 		sizes[type] += sizeof (sym);
864843e1988Sjohnlev 		sz = strlen(name) + 1;
865843e1988Sjohnlev 		sizes[XKB_WALK_STR] += sz;
866843e1988Sjohnlev 
867843e1988Sjohnlev 		if (buf != NULL) {
868843e1988Sjohnlev 			if (types & type) {
869843e1988Sjohnlev 				bcopy(&sym, *buf, sizeof (sym));
870843e1988Sjohnlev 				*buf += sizeof (sym);
871843e1988Sjohnlev 			}
872843e1988Sjohnlev 			if (types & XKB_WALK_STR) {
873843e1988Sjohnlev 				bcopy(name, *buf, sz);
874843e1988Sjohnlev 				*buf += sz;
875843e1988Sjohnlev 			}
876843e1988Sjohnlev 		}
877843e1988Sjohnlev 
878843e1988Sjohnlev 		mdb_free(name, 1024);
879843e1988Sjohnlev 	}
880843e1988Sjohnlev 
881843e1988Sjohnlev 	return (1);
882843e1988Sjohnlev }
883843e1988Sjohnlev 
884843e1988Sjohnlev static int
885843e1988Sjohnlev xkb_walk_syms(xkb_t *xkb, uintptr_t modhead, char **buf,
886843e1988Sjohnlev     size_t *sizes, int types)
887843e1988Sjohnlev {
888843e1988Sjohnlev 	uintptr_t modctl = modhead;
889843e1988Sjohnlev 	uintptr_t modulep;
890843e1988Sjohnlev 	struct module module;
891843e1988Sjohnlev 	uintptr_t sym_count;
892843e1988Sjohnlev 	uintptr_t sym_addr;
893843e1988Sjohnlev 	uintptr_t str_addr;
894843e1988Sjohnlev 	size_t max_iter = 500;
895843e1988Sjohnlev 
896843e1988Sjohnlev 	bzero(sizes, sizeof (*sizes) * (XKB_WALK_STR + 1));
897843e1988Sjohnlev 
898843e1988Sjohnlev 	/*
899843e1988Sjohnlev 	 * empty first symbol
900843e1988Sjohnlev 	 */
901843e1988Sjohnlev 	sizes[XKB_WALK_LOCAL] += sizeof (Sym);
902843e1988Sjohnlev 	sizes[XKB_WALK_STR] += 1;
903843e1988Sjohnlev 
904843e1988Sjohnlev 	if (buf != NULL) {
905843e1988Sjohnlev 		if (types & XKB_WALK_LOCAL) {
906843e1988Sjohnlev 			Sym tmp;
907843e1988Sjohnlev 			bzero(&tmp, sizeof (tmp));
908843e1988Sjohnlev 			bcopy(&tmp, *buf, sizeof (tmp));
909843e1988Sjohnlev 			*buf += sizeof (tmp);
910843e1988Sjohnlev 		}
911843e1988Sjohnlev 		if (types & XKB_WALK_STR) {
912843e1988Sjohnlev 			**buf = '\0';
913843e1988Sjohnlev 			(*buf)++;
914843e1988Sjohnlev 		}
915843e1988Sjohnlev 	}
916843e1988Sjohnlev 
917843e1988Sjohnlev 	for (;;) {
918843e1988Sjohnlev 		if (!xkb_read_word(xkb,
919843e1988Sjohnlev 		    modctl + offsetof(struct modctl, mod_mp), &modulep))
920843e1988Sjohnlev 			return (0);
921843e1988Sjohnlev 
922843e1988Sjohnlev 		if (modulep == NULL)
923843e1988Sjohnlev 			goto next;
924843e1988Sjohnlev 
925843e1988Sjohnlev 		if (!xkb_read_module(xkb, modulep, &module, &sym_addr,
926843e1988Sjohnlev 		    &sym_count, &str_addr))
927843e1988Sjohnlev 			return (0);
928843e1988Sjohnlev 
929843e1988Sjohnlev 		if ((module.flags & KOBJ_NOKSYMS))
930843e1988Sjohnlev 			goto next;
931843e1988Sjohnlev 
932843e1988Sjohnlev 		if (!xkb_read_modsyms(xkb, buf, sizes, types, sym_addr,
933843e1988Sjohnlev 		    str_addr, sym_count))
934843e1988Sjohnlev 			return (0);
935843e1988Sjohnlev 
936843e1988Sjohnlev next:
937843e1988Sjohnlev 		if (!xkb_read_word(xkb,
938843e1988Sjohnlev 		    modctl + offsetof(struct modctl, mod_next), &modctl))
939843e1988Sjohnlev 			return (0);
940843e1988Sjohnlev 
941843e1988Sjohnlev 		if (modctl == modhead)
942843e1988Sjohnlev 			break;
943843e1988Sjohnlev 		/*
944843e1988Sjohnlev 		 * Try and prevent us looping forever if we have a broken list.
945843e1988Sjohnlev 		 */
946843e1988Sjohnlev 		if (--max_iter == 0)
947843e1988Sjohnlev 			break;
948843e1988Sjohnlev 	}
949843e1988Sjohnlev 
950843e1988Sjohnlev 	return (1);
951843e1988Sjohnlev }
952843e1988Sjohnlev 
953843e1988Sjohnlev /*
954843e1988Sjohnlev  * Userspace equivalent of ksyms_snapshot().  Since we don't have a namelist
955843e1988Sjohnlev  * file for hypervisor images, we fabricate one here using code similar
956843e1988Sjohnlev  * to that of /dev/ksyms.
957843e1988Sjohnlev  */
958843e1988Sjohnlev static int
959843e1988Sjohnlev xkb_build_ksyms(xkb_t *xkb)
960843e1988Sjohnlev {
961843e1988Sjohnlev 	debug_info_t *info = &xkb->xkb_info;
962843e1988Sjohnlev 	size_t sizes[XKB_WALK_STR + 1];
963843e1988Sjohnlev 	xkb_namelist_t *hdr;
964843e1988Sjohnlev 	char *buf;
965843e1988Sjohnlev 	struct modctl modules;
966843e1988Sjohnlev 	uintptr_t module;
967843e1988Sjohnlev 	Shdr *shp;
968843e1988Sjohnlev 
969843e1988Sjohnlev 	if (xkb_read(xkb, info->di_modules, &modules,
970843e1988Sjohnlev 	    sizeof (struct modctl)) != sizeof (struct modctl))
971843e1988Sjohnlev 		return (0);
972843e1988Sjohnlev 
973843e1988Sjohnlev 	module = (uintptr_t)modules.mod_mp;
974843e1988Sjohnlev 
975843e1988Sjohnlev 	if (!xkb_walk_syms(xkb, info->di_modules, NULL, sizes,
976843e1988Sjohnlev 	    XKB_WALK_LOCAL | XKB_WALK_GLOBAL | XKB_WALK_STR))
977843e1988Sjohnlev 		return (0);
978843e1988Sjohnlev 
979843e1988Sjohnlev 	xkb->xkb_namesize = sizeof (xkb_namelist_t);
980843e1988Sjohnlev 	xkb->xkb_namesize += sizes[XKB_WALK_LOCAL];
981843e1988Sjohnlev 	xkb->xkb_namesize += sizes[XKB_WALK_GLOBAL];
982843e1988Sjohnlev 	xkb->xkb_namesize += sizes[XKB_WALK_STR];
983843e1988Sjohnlev 
984843e1988Sjohnlev 	if ((xkb->xkb_namelist = mdb_zalloc(xkb->xkb_namesize, UM_SLEEP))
985843e1988Sjohnlev 	    == NULL)
986843e1988Sjohnlev 		return (0);
987843e1988Sjohnlev 
988843e1988Sjohnlev 	/* LINTED - alignment */
989843e1988Sjohnlev 	hdr = (xkb_namelist_t *)xkb->xkb_namelist;
990843e1988Sjohnlev 
991843e1988Sjohnlev 	if (xkb_read(xkb, module + offsetof(struct module, hdr),
992843e1988Sjohnlev 	    &hdr->kh_elf_hdr, sizeof (Ehdr)) != sizeof (Ehdr))
993843e1988Sjohnlev 		return (0);
994843e1988Sjohnlev 
995843e1988Sjohnlev 	hdr->kh_elf_hdr.e_phoff = offsetof(xkb_namelist_t, kh_text_phdr);
996843e1988Sjohnlev 	hdr->kh_elf_hdr.e_shoff = offsetof(xkb_namelist_t, kh_shdr);
997843e1988Sjohnlev 	hdr->kh_elf_hdr.e_phnum = 2;
998843e1988Sjohnlev 	hdr->kh_elf_hdr.e_shnum = XKB_SHDR_NUM;
999843e1988Sjohnlev 	hdr->kh_elf_hdr.e_shstrndx = XKB_SHDR_SHSTRTAB;
1000843e1988Sjohnlev 
1001843e1988Sjohnlev 	hdr->kh_text_phdr.p_type = PT_LOAD;
1002843e1988Sjohnlev 	hdr->kh_text_phdr.p_vaddr = (Addr)info->di_s_text;
1003843e1988Sjohnlev 	hdr->kh_text_phdr.p_memsz = (Word)(info->di_e_text - info->di_s_text);
1004843e1988Sjohnlev 	hdr->kh_text_phdr.p_flags = PF_R | PF_X;
1005843e1988Sjohnlev 
1006843e1988Sjohnlev 	hdr->kh_data_phdr.p_type = PT_LOAD;
1007843e1988Sjohnlev 	hdr->kh_data_phdr.p_vaddr = (Addr)info->di_s_data;
1008843e1988Sjohnlev 	hdr->kh_data_phdr.p_memsz = (Word)(info->di_e_data - info->di_s_data);
1009843e1988Sjohnlev 	hdr->kh_data_phdr.p_flags = PF_R | PF_W | PF_X;
1010843e1988Sjohnlev 
1011843e1988Sjohnlev 	shp = &hdr->kh_shdr[XKB_SHDR_SYMTAB];
1012843e1988Sjohnlev 	shp->sh_name = 1;	/* xkb_shstrtab[1] = ".symtab" */
1013843e1988Sjohnlev 	shp->sh_type = SHT_SYMTAB;
1014843e1988Sjohnlev 	shp->sh_offset = sizeof (xkb_namelist_t);
1015843e1988Sjohnlev 	shp->sh_size = sizes[XKB_WALK_LOCAL] + sizes[XKB_WALK_GLOBAL];
1016843e1988Sjohnlev 	shp->sh_link = XKB_SHDR_STRTAB;
1017843e1988Sjohnlev 	shp->sh_info = sizes[XKB_WALK_LOCAL] / sizeof (Sym);
1018843e1988Sjohnlev 	shp->sh_addralign = sizeof (Addr);
1019843e1988Sjohnlev 	shp->sh_entsize = sizeof (Sym);
1020843e1988Sjohnlev 	shp->sh_addr = (Addr)(xkb->xkb_namelist + shp->sh_offset);
1021843e1988Sjohnlev 
1022843e1988Sjohnlev 
1023843e1988Sjohnlev 	shp = &hdr->kh_shdr[XKB_SHDR_STRTAB];
1024843e1988Sjohnlev 	shp->sh_name = 9;	/* xkb_shstrtab[9] = ".strtab" */
1025843e1988Sjohnlev 	shp->sh_type = SHT_STRTAB;
1026843e1988Sjohnlev 	shp->sh_offset = sizeof (xkb_namelist_t) +
1027843e1988Sjohnlev 	    sizes[XKB_WALK_LOCAL] + sizes[XKB_WALK_GLOBAL];
1028843e1988Sjohnlev 	shp->sh_size = sizes[XKB_WALK_STR];
1029843e1988Sjohnlev 	shp->sh_addralign = 1;
1030843e1988Sjohnlev 	shp->sh_addr = (Addr)(xkb->xkb_namelist + shp->sh_offset);
1031843e1988Sjohnlev 
1032843e1988Sjohnlev 
1033843e1988Sjohnlev 	shp = &hdr->kh_shdr[XKB_SHDR_SHSTRTAB];
1034843e1988Sjohnlev 	shp->sh_name = 17;	/* xkb_shstrtab[17] = ".shstrtab" */
1035843e1988Sjohnlev 	shp->sh_type = SHT_STRTAB;
1036843e1988Sjohnlev 	shp->sh_offset = offsetof(xkb_namelist_t, shstrings);
1037843e1988Sjohnlev 	shp->sh_size = sizeof (xkb_shstrtab);
1038843e1988Sjohnlev 	shp->sh_addralign = 1;
1039843e1988Sjohnlev 	shp->sh_addr = (Addr)(xkb->xkb_namelist + shp->sh_offset);
1040843e1988Sjohnlev 
1041843e1988Sjohnlev 	bcopy(xkb_shstrtab, hdr->shstrings, sizeof (xkb_shstrtab));
1042843e1988Sjohnlev 
1043843e1988Sjohnlev 	buf = xkb->xkb_namelist + sizeof (xkb_namelist_t);
1044843e1988Sjohnlev 
1045843e1988Sjohnlev 	if (!xkb_walk_syms(xkb, info->di_modules, &buf, sizes,
1046843e1988Sjohnlev 	    XKB_WALK_LOCAL))
1047843e1988Sjohnlev 		return (0);
1048843e1988Sjohnlev 	if (!xkb_walk_syms(xkb, info->di_modules, &buf, sizes,
1049843e1988Sjohnlev 	    XKB_WALK_GLOBAL))
1050843e1988Sjohnlev 		return (0);
1051843e1988Sjohnlev 	if (!xkb_walk_syms(xkb, info->di_modules, &buf, sizes,
1052843e1988Sjohnlev 	    XKB_WALK_STR))
1053843e1988Sjohnlev 		return (0);
1054843e1988Sjohnlev 
1055843e1988Sjohnlev 	return (1);
1056843e1988Sjohnlev }
1057843e1988Sjohnlev 
1058a576ab5bSrab static xkb_t *
1059a576ab5bSrab xkb_open_core(xkb_t *xkb)
1060843e1988Sjohnlev {
1061a576ab5bSrab 	xkb_core_t *xc = &xkb->xkb_core;
1062843e1988Sjohnlev 	size_t sz;
1063*349b53ddSStuart Maybee 	int i;
1064*349b53ddSStuart Maybee 	struct vcpu_guest_context *vcp;
1065843e1988Sjohnlev 
1066a576ab5bSrab 	xkb->xkb_type = XKB_FORMAT_CORE;
1067843e1988Sjohnlev 
1068a576ab5bSrab 	if ((xkb->xkb_fd = open64(xkb->xkb_path, O_RDONLY)) == -1)
1069a576ab5bSrab 		return (xkb_fail(xkb, "cannot open %s", xkb->xkb_path));
1070843e1988Sjohnlev 
1071a576ab5bSrab 	if (pread64(xkb->xkb_fd, &xc->xc_hdr, sizeof (xc->xc_hdr), 0) !=
1072a576ab5bSrab 	    sizeof (xc->xc_hdr))
1073a576ab5bSrab 		return (xkb_fail(xkb, "invalid dump file"));
1074843e1988Sjohnlev 
1075a576ab5bSrab 	if (xc->xc_hdr.xch_magic == XC_CORE_MAGIC_HVM)
1076a576ab5bSrab 		return (xkb_fail(xkb, "cannot process HVM images"));
1077843e1988Sjohnlev 
1078a576ab5bSrab 	if (xc->xc_hdr.xch_magic != XC_CORE_MAGIC) {
1079a576ab5bSrab 		return (xkb_fail(xkb, "invalid magic %d",
1080a576ab5bSrab 		    xc->xc_hdr.xch_magic));
1081a576ab5bSrab 	}
1082843e1988Sjohnlev 
1083a576ab5bSrab 	/*
1084a576ab5bSrab 	 * With FORMAT_CORE, all pages are in the dump (non-existing
1085a576ab5bSrab 	 * ones are zeroed out).
1086a576ab5bSrab 	 */
1087a576ab5bSrab 	xkb->xkb_nr_pages = xc->xc_hdr.xch_nr_pages;
1088a576ab5bSrab 	xkb->xkb_pages_off = xc->xc_hdr.xch_pages_offset;
1089a576ab5bSrab 	xkb->xkb_max_pfn = xc->xc_hdr.xch_nr_pages - 1;
1090a576ab5bSrab 	xkb->xkb_nr_vcpus = xc->xc_hdr.xch_nr_vcpus;
1091843e1988Sjohnlev 
1092*349b53ddSStuart Maybee 	sz = xkb->xkb_nr_vcpus * sizeof (struct vcpu_guest_context);
1093*349b53ddSStuart Maybee 	xkb->xkb_vcpu_data_sz = sz;
1094*349b53ddSStuart Maybee 	xkb->xkb_vcpu_data = mdb_alloc(sz, UM_SLEEP);
1095843e1988Sjohnlev 
1096*349b53ddSStuart Maybee 	if (pread64(xkb->xkb_fd, xkb->xkb_vcpu_data, sz,
1097a576ab5bSrab 	    xc->xc_hdr.xch_ctxt_offset) != sz)
1098a576ab5bSrab 		return (xkb_fail(xkb, "cannot read VCPU contexts"));
1099843e1988Sjohnlev 
1100*349b53ddSStuart Maybee 	sz = xkb->xkb_nr_vcpus * sizeof (struct vcpu_guest_context *);
1101*349b53ddSStuart Maybee 	xkb->xkb_vcpus = mdb_alloc(sz, UM_SLEEP);
1102*349b53ddSStuart Maybee 
1103*349b53ddSStuart Maybee 	vcp = xkb->xkb_vcpu_data;
1104*349b53ddSStuart Maybee 	for (i = 0; i < xkb->xkb_nr_vcpus; i++)
1105*349b53ddSStuart Maybee 		xkb->xkb_vcpus[i] = &vcp[i];
1106*349b53ddSStuart Maybee 
1107a576ab5bSrab 	/*
1108a576ab5bSrab 	 * Try to map all the data pages. If we can't, fall back to the
1109a576ab5bSrab 	 * window/pread() approach, which is significantly slower.
1110a576ab5bSrab 	 */
1111a576ab5bSrab 	xkb->xkb_pages = mmap(NULL, PAGE_SIZE * xkb->xkb_nr_pages,
1112a576ab5bSrab 	    PROT_READ, MAP_SHARED, xkb->xkb_fd, xc->xc_hdr.xch_pages_offset);
1113a576ab5bSrab 
1114a576ab5bSrab 	if (xkb->xkb_pages == (char *)MAP_FAILED)
1115a576ab5bSrab 		xkb->xkb_pages = NULL;
1116a576ab5bSrab 
1117a576ab5bSrab 	/*
1118a576ab5bSrab 	 * We'd like to adapt for correctness' sake, but we have no way of
1119a576ab5bSrab 	 * detecting a PAE guest, since cr4 writes are disallowed.
1120a576ab5bSrab 	 */
1121a576ab5bSrab 	xkb->xkb_is_pae = 1;
1122a576ab5bSrab 
1123a576ab5bSrab 	if (!xkb_map_p2m(xkb))
1124a576ab5bSrab 		return (NULL);
1125a576ab5bSrab 
1126a576ab5bSrab 	return (xkb);
1127a576ab5bSrab }
1128a576ab5bSrab 
1129a576ab5bSrab static xkb_t *
1130a576ab5bSrab xkb_open_elf(xkb_t *xkb)
1131a576ab5bSrab {
1132a576ab5bSrab 	xkb_elf_t *xe = &xkb->xkb_elf;
1133a576ab5bSrab 	mdb_gelf_sect_t *sect;
1134a576ab5bSrab 	char *notes;
1135a576ab5bSrab 	char *pos;
1136a576ab5bSrab 	mdb_io_t *io;
1137*349b53ddSStuart Maybee 	size_t sz;
1138*349b53ddSStuart Maybee 	int i;
1139*349b53ddSStuart Maybee 	void *dp;
1140a576ab5bSrab 
1141a576ab5bSrab 	if ((io = mdb_fdio_create_path(NULL, xkb->xkb_path,
1142a576ab5bSrab 	    O_RDONLY, 0)) == NULL)
1143a576ab5bSrab 		return (xkb_fail(xkb, "failed to open"));
1144a576ab5bSrab 
1145a576ab5bSrab 	xe->xe_gelf = mdb_gelf_create(io, ET_NONE, GF_FILE);
1146a576ab5bSrab 
1147a576ab5bSrab 	if (xe->xe_gelf == NULL) {
1148a576ab5bSrab 		mdb_io_destroy(io);
1149a576ab5bSrab 		return (xkb);
1150843e1988Sjohnlev 	}
1151843e1988Sjohnlev 
1152a576ab5bSrab 	xkb->xkb_fd = mdb_fdio_fileno(io);
1153843e1988Sjohnlev 
1154a576ab5bSrab 	sect = mdb_gelf_sect_by_name(xe->xe_gelf, ".note.Xen");
1155843e1988Sjohnlev 
1156a576ab5bSrab 	if (sect == NULL)
1157a576ab5bSrab 		return (xkb);
1158a576ab5bSrab 
1159a576ab5bSrab 	if ((notes = mdb_gelf_sect_load(xe->xe_gelf, sect)) == NULL)
1160a576ab5bSrab 		return (xkb);
1161a576ab5bSrab 
1162a576ab5bSrab 	/*
1163a576ab5bSrab 	 * Now we know this is indeed a hypervisor core dump, even if
1164a576ab5bSrab 	 * it's corrupted.
1165a576ab5bSrab 	 */
1166a576ab5bSrab 	xkb->xkb_type = XKB_FORMAT_ELF;
1167a576ab5bSrab 
1168a576ab5bSrab 	for (pos = notes; pos < notes + sect->gs_shdr.sh_size; ) {
1169a576ab5bSrab 		/* LINTED - alignment */
1170a576ab5bSrab 		Elf64_Nhdr *nhdr = (Elf64_Nhdr *)pos;
1171a576ab5bSrab 		uint64_t vers;
1172a576ab5bSrab 		char *desc;
1173a576ab5bSrab 		char *name;
1174a576ab5bSrab 
1175a576ab5bSrab 		name = pos + sizeof (*nhdr);
1176a576ab5bSrab 		desc = (char *)P2ROUNDUP((uintptr_t)name + nhdr->n_namesz, 4);
1177a576ab5bSrab 
1178a576ab5bSrab 		pos = desc + nhdr->n_descsz;
1179a576ab5bSrab 
1180a576ab5bSrab 		switch (nhdr->n_type) {
1181a576ab5bSrab 		case XEN_ELFNOTE_DUMPCORE_NONE:
1182a576ab5bSrab 			break;
1183843e1988Sjohnlev 
1184a576ab5bSrab 		case XEN_ELFNOTE_DUMPCORE_HEADER:
1185a576ab5bSrab 			if (nhdr->n_descsz != sizeof (struct xc_elf_header)) {
1186a576ab5bSrab 				return (xkb_fail(xkb, "invalid ELF note "
1187a576ab5bSrab 				    "XEN_ELFNOTE_DUMPCORE_HEADER\n"));
1188a576ab5bSrab 			}
1189a576ab5bSrab 
1190a576ab5bSrab 			bcopy(desc, &xe->xe_hdr,
1191a576ab5bSrab 			    sizeof (struct xc_elf_header));
1192a576ab5bSrab 			break;
1193a576ab5bSrab 
1194a576ab5bSrab 		case XEN_ELFNOTE_DUMPCORE_XEN_VERSION:
1195*349b53ddSStuart Maybee 			if (nhdr->n_descsz < sizeof (struct xc_elf_version)) {
1196a576ab5bSrab 				return (xkb_fail(xkb, "invalid ELF note "
1197a576ab5bSrab 				    "XEN_ELFNOTE_DUMPCORE_XEN_VERSION\n"));
1198a576ab5bSrab 			}
1199a576ab5bSrab 
1200a576ab5bSrab 			bcopy(desc, &xe->xe_version,
1201a576ab5bSrab 			    sizeof (struct xc_elf_version));
1202a576ab5bSrab 			break;
1203a576ab5bSrab 
1204a576ab5bSrab 		case XEN_ELFNOTE_DUMPCORE_FORMAT_VERSION:
1205a576ab5bSrab 			/* LINTED - alignment */
1206a576ab5bSrab 			vers = *((uint64_t *)desc);
1207a576ab5bSrab 			if ((vers >> 32) != 0) {
1208a576ab5bSrab 				return (xkb_fail(xkb, "unknown major "
1209a576ab5bSrab 				    "version %d (expected 0)\n",
1210a576ab5bSrab 				    (int)(vers >> 32)));
1211a576ab5bSrab 			}
1212a576ab5bSrab 
1213a576ab5bSrab 			if ((vers & 0xffffffff) != 1) {
1214a576ab5bSrab 				mdb_warn("unexpected dump minor number "
1215a576ab5bSrab 				    "version %d (expected 1)\n",
1216a576ab5bSrab 				    (int)(vers & 0xffffffff));
1217a576ab5bSrab 			}
1218a576ab5bSrab 			break;
1219a576ab5bSrab 
1220a576ab5bSrab 		default:
1221a576ab5bSrab 			mdb_warn("unknown ELF note %d(%s)\n",
1222a576ab5bSrab 			    nhdr->n_type, name);
1223a576ab5bSrab 			break;
1224a576ab5bSrab 		}
1225a576ab5bSrab 	}
1226a576ab5bSrab 
12275d2eda97SJohn Levon 	xkb->xkb_is_hvm = xe->xe_hdr.xeh_magic == XC_CORE_MAGIC_HVM;
1228843e1988Sjohnlev 
12295d2eda97SJohn Levon 	if (xe->xe_hdr.xeh_magic != XC_CORE_MAGIC &&
12305d2eda97SJohn Levon 	    xe->xe_hdr.xeh_magic != XC_CORE_MAGIC_HVM) {
1231a576ab5bSrab 		return (xkb_fail(xkb, "invalid magic %d",
1232a576ab5bSrab 		    xe->xe_hdr.xeh_magic));
1233a576ab5bSrab 	}
1234a576ab5bSrab 
1235a576ab5bSrab 	xkb->xkb_nr_pages = xe->xe_hdr.xeh_nr_pages;
1236a576ab5bSrab 	xkb->xkb_is_pae = (strstr(xe->xe_version.xev_capabilities,
1237a576ab5bSrab 	    "x86_32p") != NULL);
1238a576ab5bSrab 
1239a576ab5bSrab 	sect = mdb_gelf_sect_by_name(xe->xe_gelf, ".xen_prstatus");
1240a576ab5bSrab 
1241a576ab5bSrab 	if (sect == NULL)
1242a576ab5bSrab 		return (xkb_fail(xkb, "cannot find section .xen_prstatus"));
1243a576ab5bSrab 
1244*349b53ddSStuart Maybee 	if (sect->gs_shdr.sh_entsize < sizeof (vcpu_guest_context_t))
1245a576ab5bSrab 		return (xkb_fail(xkb, "invalid section .xen_prstatus"));
1246a576ab5bSrab 
1247a576ab5bSrab 	xkb->xkb_nr_vcpus = sect->gs_shdr.sh_size / sect->gs_shdr.sh_entsize;
1248a576ab5bSrab 
1249*349b53ddSStuart Maybee 	xkb->xkb_vcpu_data = mdb_gelf_sect_load(xe->xe_gelf, sect);
1250*349b53ddSStuart Maybee 	if (xkb->xkb_vcpu_data == NULL)
1251a576ab5bSrab 		return (xkb_fail(xkb, "cannot load section .xen_prstatus"));
1252*349b53ddSStuart Maybee 	xkb->xkb_vcpu_data_sz = sect->gs_shdr.sh_size;
1253*349b53ddSStuart Maybee 
1254*349b53ddSStuart Maybee 	/*
1255*349b53ddSStuart Maybee 	 * The vcpu_guest_context structures saved in the core file
1256*349b53ddSStuart Maybee 	 * are actually unions of the 64-bit and 32-bit versions.
1257*349b53ddSStuart Maybee 	 * Don't rely on the entry size to match the size of
1258*349b53ddSStuart Maybee 	 * the structure, but set up an array of pointers.
1259*349b53ddSStuart Maybee 	 */
1260*349b53ddSStuart Maybee 	sz = xkb->xkb_nr_vcpus * sizeof (struct vcpu_guest_context *);
1261*349b53ddSStuart Maybee 	xkb->xkb_vcpus = mdb_alloc(sz, UM_SLEEP);
1262*349b53ddSStuart Maybee 	for (i = 0; i < xkb->xkb_nr_vcpus; i++) {
1263*349b53ddSStuart Maybee 		dp = ((char *)xkb->xkb_vcpu_data +
1264*349b53ddSStuart Maybee 		    i * sect->gs_shdr.sh_entsize);
1265*349b53ddSStuart Maybee 		xkb->xkb_vcpus[i] = dp;
1266*349b53ddSStuart Maybee 	}
1267a576ab5bSrab 
1268a576ab5bSrab 	sect = mdb_gelf_sect_by_name(xe->xe_gelf, ".xen_pages");
1269a576ab5bSrab 
1270a576ab5bSrab 	if (sect == NULL)
1271a576ab5bSrab 		return (xkb_fail(xkb, "cannot find section .xen_pages"));
1272a576ab5bSrab 
1273a576ab5bSrab 	if (!PAGE_ALIGNED(sect->gs_shdr.sh_offset))
1274a576ab5bSrab 		return (xkb_fail(xkb, ".xen_pages is not page aligned"));
1275a576ab5bSrab 
1276a576ab5bSrab 	if (sect->gs_shdr.sh_entsize != PAGE_SIZE)
1277a576ab5bSrab 		return (xkb_fail(xkb, "invalid section .xen_pages"));
1278a576ab5bSrab 
1279a576ab5bSrab 	xkb->xkb_pages_off = sect->gs_shdr.sh_offset;
1280a576ab5bSrab 
1281843e1988Sjohnlev 	/*
1282843e1988Sjohnlev 	 * Try to map all the data pages. If we can't, fall back to the
1283843e1988Sjohnlev 	 * window/pread() approach, which is significantly slower.
1284843e1988Sjohnlev 	 */
1285a576ab5bSrab 	xkb->xkb_pages = mmap(NULL, PAGE_SIZE * xkb->xkb_nr_pages,
1286a576ab5bSrab 	    PROT_READ, MAP_SHARED, xkb->xkb_fd, xkb->xkb_pages_off);
1287843e1988Sjohnlev 
1288843e1988Sjohnlev 	if (xkb->xkb_pages == (char *)MAP_FAILED)
1289843e1988Sjohnlev 		xkb->xkb_pages = NULL;
1290843e1988Sjohnlev 
12915d2eda97SJohn Levon 	if (xkb->xkb_is_hvm) {
12925d2eda97SJohn Levon 		if (!xkb_build_fake_p2m(xkb))
12935d2eda97SJohn Levon 			return (NULL);
12945d2eda97SJohn Levon 	} else {
12955d2eda97SJohn Levon 		if (!xkb_build_p2m(xkb))
12965d2eda97SJohn Levon 			return (NULL);
12975d2eda97SJohn Levon 	}
1298a576ab5bSrab 
1299a576ab5bSrab 	return (xkb);
1300a576ab5bSrab }
1301a576ab5bSrab 
1302a576ab5bSrab static void
1303a576ab5bSrab xkb_init_mmu(xkb_t *xkb)
1304a576ab5bSrab {
1305843e1988Sjohnlev #if defined(__amd64)
1306843e1988Sjohnlev 	xkb->xkb_mmu.mi_max = 3;
1307843e1988Sjohnlev 	xkb->xkb_mmu.mi_shift[0] = 12;
1308843e1988Sjohnlev 	xkb->xkb_mmu.mi_shift[1] = 21;
1309843e1988Sjohnlev 	xkb->xkb_mmu.mi_shift[2] = 30;
1310843e1988Sjohnlev 	xkb->xkb_mmu.mi_shift[3] = 39;
1311843e1988Sjohnlev 	xkb->xkb_mmu.mi_ptes = 512;
1312843e1988Sjohnlev 	xkb->xkb_mmu.mi_ptesize = 8;
1313843e1988Sjohnlev #elif defined(__i386)
1314a576ab5bSrab 	if (xkb->xkb_is_pae) {
1315a576ab5bSrab 		xkb->xkb_mmu.mi_max = 2;
1316a576ab5bSrab 		xkb->xkb_mmu.mi_shift[0] = 12;
1317a576ab5bSrab 		xkb->xkb_mmu.mi_shift[1] = 21;
1318a576ab5bSrab 		xkb->xkb_mmu.mi_shift[2] = 30;
1319a576ab5bSrab 		xkb->xkb_mmu.mi_ptes = 512;
1320a576ab5bSrab 		xkb->xkb_mmu.mi_ptesize = 8;
1321a576ab5bSrab 	} else {
1322a576ab5bSrab 		xkb->xkb_mmu.mi_max = 1;
1323a576ab5bSrab 		xkb->xkb_mmu.mi_shift[0] = 12;
1324a576ab5bSrab 		xkb->xkb_mmu.mi_shift[1] = 22;
1325a576ab5bSrab 		xkb->xkb_mmu.mi_ptes = 1024;
1326a576ab5bSrab 		xkb->xkb_mmu.mi_ptesize = 4;
1327a576ab5bSrab 	}
1328843e1988Sjohnlev #endif
1329a576ab5bSrab }
1330843e1988Sjohnlev 
1331a576ab5bSrab /*ARGSUSED*/
1332a576ab5bSrab xkb_t *
1333a576ab5bSrab xkb_open(const char *namelist, const char *corefile, const char *swapfile,
1334a576ab5bSrab     int flag, const char *err)
1335a576ab5bSrab {
13365d2eda97SJohn Levon 	uintptr_t debug_info = DEBUG_INFO;
1337a576ab5bSrab 	struct stat64 corestat;
1338a576ab5bSrab 	xkb_t *xkb = NULL;
1339a576ab5bSrab 	size_t i;
1340a576ab5bSrab 
1341a576ab5bSrab 	if (stat64(corefile, &corestat) == -1)
1342a576ab5bSrab 		return (xkb_fail(xkb, "cannot stat %s", corefile));
1343a576ab5bSrab 
1344a576ab5bSrab 	if (flag != O_RDONLY)
1345a576ab5bSrab 		return (xkb_fail(xkb, "invalid open flags"));
1346a576ab5bSrab 
1347a576ab5bSrab 	xkb = mdb_zalloc(sizeof (*xkb), UM_SLEEP);
1348a576ab5bSrab 
13495d2eda97SJohn Levon 	for (i = 0; i < 4; i++) {
13505d2eda97SJohn Levon 		xkb->xkb_pt_map[i].mm_mfn = MFN_INVALID;
1351a576ab5bSrab 		xkb->xkb_pt_map[i].mm_map = (char *)MAP_FAILED;
13525d2eda97SJohn Levon 	}
1353a576ab5bSrab 
1354a576ab5bSrab 	xkb->xkb_type = XKB_FORMAT_UNKNOWN;
13555d2eda97SJohn Levon 	xkb->xkb_map.mm_mfn = MFN_INVALID;
1356a576ab5bSrab 	xkb->xkb_map.mm_map = (char *)MAP_FAILED;
1357a576ab5bSrab 	xkb->xkb_core.xc_p2m_buf = (char *)MAP_FAILED;
1358a576ab5bSrab 	xkb->xkb_fd = -1;
1359a576ab5bSrab 
1360a576ab5bSrab 	xkb->xkb_path = strdup(corefile);
1361a576ab5bSrab 
1362a576ab5bSrab 	if ((xkb = xkb_open_elf(xkb)) == NULL)
1363843e1988Sjohnlev 		return (NULL);
1364843e1988Sjohnlev 
1365a576ab5bSrab 	if (xkb->xkb_type == XKB_FORMAT_UNKNOWN) {
1366a576ab5bSrab 		if (!xkb_open_core(xkb))
1367a576ab5bSrab 			return (NULL);
1368a576ab5bSrab 	}
1369a576ab5bSrab 
1370a576ab5bSrab 	xkb_init_mmu(xkb);
1371a576ab5bSrab 
1372843e1988Sjohnlev 	if (!xkb_build_m2p(xkb))
1373843e1988Sjohnlev 		return (NULL);
1374843e1988Sjohnlev 
13755d2eda97SJohn Levon 	if (xkb->xkb_is_hvm)
13765d2eda97SJohn Levon 		debug_info = DEBUG_INFO_HVM;
13775d2eda97SJohn Levon 
13785d2eda97SJohn Levon 	if (xkb_read(xkb, debug_info, &xkb->xkb_info,
1379843e1988Sjohnlev 	    sizeof (xkb->xkb_info)) != sizeof (xkb->xkb_info))
1380843e1988Sjohnlev 		return (xkb_fail(xkb, "cannot read debug_info"));
1381843e1988Sjohnlev 
1382843e1988Sjohnlev 	if (xkb->xkb_info.di_magic != DEBUG_INFO_MAGIC) {
1383843e1988Sjohnlev 		return (xkb_fail(xkb, "invalid debug info magic %d",
1384843e1988Sjohnlev 		    xkb->xkb_info.di_magic));
1385843e1988Sjohnlev 	}
1386843e1988Sjohnlev 
1387843e1988Sjohnlev 	if (xkb->xkb_info.di_version != DEBUG_INFO_VERSION) {
1388843e1988Sjohnlev 		return (xkb_fail(xkb, "unknown debug info version %d",
1389843e1988Sjohnlev 		    xkb->xkb_info.di_version));
1390843e1988Sjohnlev 	}
1391843e1988Sjohnlev 
1392843e1988Sjohnlev 	if (!xkb_build_ksyms(xkb))
1393843e1988Sjohnlev 		return (xkb_fail(xkb, "cannot construct namelist"));
1394843e1988Sjohnlev 
1395843e1988Sjohnlev 	return (xkb);
1396843e1988Sjohnlev }
1397843e1988Sjohnlev 
1398843e1988Sjohnlev int
1399843e1988Sjohnlev xkb_close(xkb_t *xkb)
1400843e1988Sjohnlev {
1401*349b53ddSStuart Maybee 	size_t i, sz;
1402843e1988Sjohnlev 
1403843e1988Sjohnlev 	if (xkb == NULL)
1404843e1988Sjohnlev 		return (0);
1405843e1988Sjohnlev 
1406843e1988Sjohnlev 	if (xkb->xkb_m2p != NULL) {
1407843e1988Sjohnlev 		mdb_free(xkb->xkb_m2p,
1408843e1988Sjohnlev 		    (xkb->xkb_max_mfn + 1) * sizeof (xen_pfn_t));
1409843e1988Sjohnlev 	}
1410843e1988Sjohnlev 
1411843e1988Sjohnlev 	if (xkb->xkb_pages != NULL) {
1412843e1988Sjohnlev 		(void) munmap((void *)xkb->xkb_pages,
1413a576ab5bSrab 		    PAGE_SIZE * xkb->xkb_nr_pages);
1414843e1988Sjohnlev 	} else {
1415843e1988Sjohnlev 		for (i = 0; i < 4; i++) {
1416843e1988Sjohnlev 			char *addr = xkb->xkb_pt_map[i].mm_map;
1417843e1988Sjohnlev 			if (addr != (char *)MAP_FAILED)
1418843e1988Sjohnlev 				(void) munmap((void *)addr, PAGE_SIZE);
1419843e1988Sjohnlev 		}
1420843e1988Sjohnlev 		if (xkb->xkb_map.mm_map != (char *)MAP_FAILED) {
1421843e1988Sjohnlev 			(void) munmap((void *)xkb->xkb_map.mm_map,
1422843e1988Sjohnlev 			    PAGE_SIZE);
1423843e1988Sjohnlev 		}
1424843e1988Sjohnlev 	}
1425843e1988Sjohnlev 
1426843e1988Sjohnlev 	if (xkb->xkb_namelist != NULL)
1427843e1988Sjohnlev 		mdb_free(xkb->xkb_namelist, xkb->xkb_namesize);
1428843e1988Sjohnlev 
1429a576ab5bSrab 	if (xkb->xkb_type == XKB_FORMAT_ELF) {
1430a576ab5bSrab 		xkb_elf_t *xe = &xkb->xkb_elf;
1431a576ab5bSrab 
1432a576ab5bSrab 		if (xe->xe_gelf != NULL)
1433a576ab5bSrab 			mdb_gelf_destroy(xe->xe_gelf);
1434a576ab5bSrab 
1435a576ab5bSrab 		sz = sizeof (xen_pfn_t) * (xkb->xkb_max_pfn + 1);
1436a576ab5bSrab 
1437a576ab5bSrab 		if (xkb->xkb_p2m != NULL)
1438a576ab5bSrab 			mdb_free(xkb->xkb_p2m, sz);
1439a576ab5bSrab 
1440a576ab5bSrab 		sz = sizeof (size_t) * (xkb->xkb_max_pfn + 1);
1441a576ab5bSrab 
1442a576ab5bSrab 		if (xe->xe_off != NULL)
1443a576ab5bSrab 			mdb_free(xe->xe_off, sz);
1444*349b53ddSStuart Maybee 
1445a576ab5bSrab 	} else if (xkb->xkb_type == XKB_FORMAT_CORE) {
1446a576ab5bSrab 		xkb_core_t *xc = &xkb->xkb_core;
1447a576ab5bSrab 
1448a576ab5bSrab 		if (xkb->xkb_fd != -1)
1449a576ab5bSrab 			(void) close(xkb->xkb_fd);
1450a576ab5bSrab 
1451a576ab5bSrab 		sz = (xkb->xkb_nr_pages * sizeof (mfn_t)) + (PAGE_SIZE * 2);
1452a576ab5bSrab 		sz = PAGE_MASK(sz);
1453a576ab5bSrab 
1454a576ab5bSrab 		if (xc->xc_p2m_buf != (xen_pfn_t *)MAP_FAILED)
1455a576ab5bSrab 			(void) munmap(xc->xc_p2m_buf, sz);
1456a576ab5bSrab 
1457*349b53ddSStuart Maybee 		if (xkb->xkb_vcpu_data != NULL)
1458*349b53ddSStuart Maybee 			mdb_free(xkb->xkb_vcpu_data, xkb->xkb_vcpu_data_sz);
1459*349b53ddSStuart Maybee 	}
1460*349b53ddSStuart Maybee 
1461*349b53ddSStuart Maybee 	if (xkb->xkb_vcpus != NULL) {
1462*349b53ddSStuart Maybee 		sz = sizeof (struct vcpu_guest_context *) *
1463*349b53ddSStuart Maybee 		    xkb->xkb_nr_vcpus;
1464*349b53ddSStuart Maybee 		mdb_free(xkb->xkb_vcpus, sz);
1465a576ab5bSrab 	}
1466843e1988Sjohnlev 
1467843e1988Sjohnlev 	free(xkb->xkb_path);
1468843e1988Sjohnlev 
1469843e1988Sjohnlev 	mdb_free(xkb, sizeof (*xkb));
1470843e1988Sjohnlev 	return (0);
1471843e1988Sjohnlev }
1472843e1988Sjohnlev 
1473843e1988Sjohnlev /*ARGSUSED*/
1474843e1988Sjohnlev static mdb_io_t *
1475843e1988Sjohnlev xkb_sym_io(xkb_t *xkb, const char *symfile)
1476843e1988Sjohnlev {
1477843e1988Sjohnlev 	mdb_io_t *io = mdb_memio_create(xkb->xkb_namelist, xkb->xkb_namesize);
1478843e1988Sjohnlev 
1479843e1988Sjohnlev 	if (io == NULL)
1480843e1988Sjohnlev 		mdb_warn("failed to create namelist from %s", xkb->xkb_path);
1481843e1988Sjohnlev 
1482843e1988Sjohnlev 	return (io);
1483843e1988Sjohnlev }
1484843e1988Sjohnlev 
1485843e1988Sjohnlev uint64_t
1486843e1988Sjohnlev xkb_vtop(xkb_t *xkb, struct as *as, uintptr_t addr)
1487843e1988Sjohnlev {
14885d2eda97SJohn Levon 	mfn_t tlmfn = xkb_cr3_to_pfn(xkb);
1489843e1988Sjohnlev 	mfn_t mfn;
1490843e1988Sjohnlev 
1491843e1988Sjohnlev 	if (as != NULL && (tlmfn = xkb_as_to_mfn(xkb, as)) == MFN_INVALID)
1492843e1988Sjohnlev 		return (-1ULL);
1493843e1988Sjohnlev 
1494843e1988Sjohnlev 	mfn = xkb_va_to_mfn(xkb, addr, tlmfn);
1495843e1988Sjohnlev 
1496843e1988Sjohnlev 	if (mfn == MFN_INVALID || mfn > xkb->xkb_max_mfn)
1497843e1988Sjohnlev 		return (-1ULL);
1498843e1988Sjohnlev 
1499843e1988Sjohnlev 	return (((uint64_t)xkb->xkb_m2p[mfn] << PAGE_SHIFT)
1500843e1988Sjohnlev 	    | PAGE_OFFSET(addr));
1501843e1988Sjohnlev }
1502843e1988Sjohnlev 
1503843e1988Sjohnlev static int
1504843e1988Sjohnlev xkb_getmregs(xkb_t *xkb, uint_t cpu, struct privmregs *mregs)
1505843e1988Sjohnlev {
1506843e1988Sjohnlev 	struct vcpu_guest_context *vcpu;
1507843e1988Sjohnlev 	struct cpu_user_regs *ur;
1508843e1988Sjohnlev 	struct regs *regs;
1509843e1988Sjohnlev 
1510a576ab5bSrab 	if (cpu >= xkb->xkb_nr_vcpus) {
1511843e1988Sjohnlev 		errno = EINVAL;
1512843e1988Sjohnlev 		return (-1);
1513843e1988Sjohnlev 	}
1514843e1988Sjohnlev 
1515843e1988Sjohnlev 	bzero(mregs, sizeof (*mregs));
1516843e1988Sjohnlev 
1517*349b53ddSStuart Maybee 	vcpu = xkb->xkb_vcpus[cpu];
1518843e1988Sjohnlev 	ur = &vcpu->user_regs;
1519843e1988Sjohnlev 	regs = &mregs->pm_gregs;
1520843e1988Sjohnlev 
1521843e1988Sjohnlev 	regs->r_ss = ur->ss;
1522843e1988Sjohnlev 	regs->r_cs = ur->cs;
1523843e1988Sjohnlev 	regs->r_ds = ur->ds;
1524843e1988Sjohnlev 	regs->r_es = ur->es;
1525843e1988Sjohnlev 	regs->r_fs = ur->fs;
1526843e1988Sjohnlev 	regs->r_gs = ur->gs;
1527843e1988Sjohnlev 	regs->r_trapno = ur->entry_vector;
1528843e1988Sjohnlev 	regs->r_err = ur->error_code;
1529843e1988Sjohnlev #ifdef __amd64
1530843e1988Sjohnlev 	regs->r_savfp = ur->rbp;
1531843e1988Sjohnlev 	regs->r_savpc = ur->rip;
1532843e1988Sjohnlev 	regs->r_rdi = ur->rdi;
1533843e1988Sjohnlev 	regs->r_rsi = ur->rsi;
1534843e1988Sjohnlev 	regs->r_rdx = ur->rdx;
1535843e1988Sjohnlev 	regs->r_rcx = ur->rcx;
1536843e1988Sjohnlev 	regs->r_r8 = ur->r8;
1537843e1988Sjohnlev 	regs->r_r9 = ur->r9;
1538843e1988Sjohnlev 	regs->r_rax = ur->rax;
1539843e1988Sjohnlev 	regs->r_rbx = ur->rbx;
1540843e1988Sjohnlev 	regs->r_rbp = ur->rbp;
1541843e1988Sjohnlev 	regs->r_r10 = ur->r10;
1542843e1988Sjohnlev 	regs->r_r11 = ur->r11;
1543843e1988Sjohnlev 	regs->r_r12 = ur->r12;
1544843e1988Sjohnlev 	regs->r_r13 = ur->r13;
1545843e1988Sjohnlev 	regs->r_r14 = ur->r14;
1546843e1988Sjohnlev 	regs->r_r15 = ur->r15;
1547843e1988Sjohnlev 	regs->r_rip = ur->rip;
1548843e1988Sjohnlev 	regs->r_rfl = ur->rflags;
1549843e1988Sjohnlev 	regs->r_rsp = ur->rsp;
1550843e1988Sjohnlev #else
1551843e1988Sjohnlev 	regs->r_savfp = ur->ebp;
1552843e1988Sjohnlev 	regs->r_savpc = ur->eip;
1553843e1988Sjohnlev 	regs->r_edi = ur->edi;
1554843e1988Sjohnlev 	regs->r_esi = ur->esi;
1555843e1988Sjohnlev 	regs->r_ebp = ur->ebp;
1556843e1988Sjohnlev 	regs->r_esp = ur->esp;
1557843e1988Sjohnlev 	regs->r_ebx = ur->ebx;
1558843e1988Sjohnlev 	regs->r_edx = ur->edx;
1559843e1988Sjohnlev 	regs->r_ecx = ur->ecx;
1560843e1988Sjohnlev 	regs->r_eax = ur->eax;
1561843e1988Sjohnlev 	regs->r_eip = ur->eip;
1562843e1988Sjohnlev 	regs->r_efl = ur->eflags;
1563843e1988Sjohnlev 	regs->r_uesp = 0;
1564843e1988Sjohnlev #endif
1565843e1988Sjohnlev 
1566843e1988Sjohnlev 	bcopy(&vcpu->ctrlreg, &mregs->pm_cr, 8 * sizeof (ulong_t));
1567843e1988Sjohnlev 	bcopy(&vcpu->debugreg, &mregs->pm_dr, 8 * sizeof (ulong_t));
1568843e1988Sjohnlev 
1569843e1988Sjohnlev 	mregs->pm_flags = PM_GREGS | PM_CRREGS | PM_DRREGS;
1570843e1988Sjohnlev 
1571843e1988Sjohnlev 	return (0);
1572843e1988Sjohnlev }
1573843e1988Sjohnlev 
1574843e1988Sjohnlev static mdb_kb_ops_t xpv_kb_ops = {
1575843e1988Sjohnlev 	.kb_open = (void *(*)())xkb_open,
1576843e1988Sjohnlev 	.kb_close = (int (*)())xkb_close,
1577843e1988Sjohnlev 	.kb_sym_io = (mdb_io_t *(*)())xkb_sym_io,
1578843e1988Sjohnlev 	.kb_kread = (ssize_t (*)())xkb_read,
1579843e1988Sjohnlev 	.kb_kwrite = (ssize_t (*)())mdb_tgt_notsup,
1580843e1988Sjohnlev 	.kb_aread = (ssize_t (*)())xkb_aread,
1581843e1988Sjohnlev 	.kb_awrite = (ssize_t (*)())mdb_tgt_notsup,
1582843e1988Sjohnlev 	.kb_pread = (ssize_t (*)())xkb_pread,
1583843e1988Sjohnlev 	.kb_pwrite = (ssize_t (*)())mdb_tgt_notsup,
1584843e1988Sjohnlev 	.kb_vtop = (uint64_t (*)())xkb_vtop,
1585843e1988Sjohnlev 	.kb_getmregs = (int (*)())xkb_getmregs
1586843e1988Sjohnlev };
1587843e1988Sjohnlev 
1588843e1988Sjohnlev mdb_kb_ops_t *
1589843e1988Sjohnlev mdb_kb_ops(void)
1590843e1988Sjohnlev {
1591843e1988Sjohnlev 	return (&xpv_kb_ops);
1592843e1988Sjohnlev }
1593843e1988Sjohnlev 
1594843e1988Sjohnlev static const mdb_dcmd_t dcmds[] = { NULL, };
1595843e1988Sjohnlev static const mdb_walker_t walkers[] = { NULL, };
1596843e1988Sjohnlev static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
1597843e1988Sjohnlev 
1598843e1988Sjohnlev const mdb_modinfo_t *
1599843e1988Sjohnlev _mdb_init(void)
1600843e1988Sjohnlev {
1601843e1988Sjohnlev 	return (&modinfo);
1602843e1988Sjohnlev }
1603843e1988Sjohnlev 
1604843e1988Sjohnlev void
1605843e1988Sjohnlev _mdb_fini(void)
1606843e1988Sjohnlev {
1607843e1988Sjohnlev }
1608