1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-NetBSD
3 *
4 * Copyright (c) 2004 Christian Limpach.
5 * Copyright (c) 2004-2006,2008 Kip Macy
6 * Copyright (c) 2008 The NetBSD Foundation, Inc.
7 * Copyright (c) 2013 Roger Pau Monn�� <roger.pau@citrix.com>
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD$");
34
35#include "opt_ddb.h"
36#include "opt_kstack_pages.h"
37
38#include <sys/param.h>
39#include <sys/bus.h>
40#include <sys/kernel.h>
41#include <sys/reboot.h>
42#include <sys/systm.h>
43#include <sys/malloc.h>
44#include <sys/linker.h>
45#include <sys/lock.h>
46#include <sys/rwlock.h>
47#include <sys/boot.h>
48#include <sys/ctype.h>
49#include <sys/mutex.h>
50#include <sys/smp.h>
51
52#include <vm/vm.h>
53#include <vm/vm_extern.h>
54#include <vm/vm_kern.h>
55#include <vm/vm_page.h>
56#include <vm/vm_map.h>
57#include <vm/vm_object.h>
58#include <vm/vm_pager.h>
59#include <vm/vm_param.h>
60
61#include <machine/_inttypes.h>
62#include <machine/intr_machdep.h>
63#include <x86/apicvar.h>
64#include <x86/init.h>
65#include <machine/pc/bios.h>
66#include <machine/smp.h>
67#include <machine/intr_machdep.h>
68#include <machine/metadata.h>
69
70#include <xen/xen-os.h>
71#include <xen/hvm.h>
72#include <xen/hypervisor.h>
73#include <xen/xenstore/xenstorevar.h>
74#include <xen/xen_pv.h>
75#include <xen/xen_msi.h>
76
77#include <xen/interface/arch-x86/hvm/start_info.h>
78#include <xen/interface/vcpu.h>
79
80#include <dev/xen/timer/timer.h>
81
82#ifdef DDB
83#include <ddb/ddb.h>
84#endif
85
86/* Native initial function */
87extern u_int64_t hammer_time(u_int64_t, u_int64_t);
88/* Xen initial function */
89uint64_t hammer_time_xen_legacy(start_info_t *, uint64_t);
90uint64_t hammer_time_xen(vm_paddr_t);
91
92#define MAX_E820_ENTRIES	128
93
94/*--------------------------- Forward Declarations ---------------------------*/
95static caddr_t xen_legacy_pvh_parse_preload_data(uint64_t);
96static caddr_t xen_pvh_parse_preload_data(uint64_t);
97static void xen_pvh_parse_memmap(caddr_t, vm_paddr_t *, int *);
98
99#ifdef SMP
100static int xen_pv_start_all_aps(void);
101#endif
102
103/*---------------------------- Extern Declarations ---------------------------*/
104#ifdef SMP
105/* Variables used by amd64 mp_machdep to start APs */
106extern char *doublefault_stack;
107extern char *mce_stack;
108extern char *nmi_stack;
109extern char *dbg_stack;
110#endif
111
112/*
113 * Placed by the linker at the end of the bss section, which is the last
114 * section loaded by Xen before loading the symtab and strtab.
115 */
116extern uint32_t end;
117
118/*-------------------------------- Global Data -------------------------------*/
119/* Xen init_ops implementation. */
120struct init_ops xen_legacy_init_ops = {
121	.parse_preload_data		= xen_legacy_pvh_parse_preload_data,
122	.early_clock_source_init	= xen_clock_init,
123	.early_delay			= xen_delay,
124	.parse_memmap			= xen_pvh_parse_memmap,
125#ifdef SMP
126	.start_all_aps			= xen_pv_start_all_aps,
127#endif
128	.msi_init			= xen_msi_init,
129};
130
131struct init_ops xen_pvh_init_ops = {
132	.parse_preload_data		= xen_pvh_parse_preload_data,
133	.early_clock_source_init	= xen_clock_init,
134	.early_delay			= xen_delay,
135	.parse_memmap			= xen_pvh_parse_memmap,
136#ifdef SMP
137	.mp_bootaddress			= mp_bootaddress,
138	.start_all_aps			= native_start_all_aps,
139#endif
140	.msi_init			= msi_init,
141};
142
143static struct bios_smap xen_smap[MAX_E820_ENTRIES];
144
145static start_info_t *legacy_start_info;
146static struct hvm_start_info *start_info;
147
148/*----------------------- Legacy PVH start_info accessors --------------------*/
149static vm_paddr_t
150legacy_get_xenstore_mfn(void)
151{
152
153	return (legacy_start_info->store_mfn);
154}
155
156static evtchn_port_t
157legacy_get_xenstore_evtchn(void)
158{
159
160	return (legacy_start_info->store_evtchn);
161}
162
163static vm_paddr_t
164legacy_get_console_mfn(void)
165{
166
167	return (legacy_start_info->console.domU.mfn);
168}
169
170static evtchn_port_t
171legacy_get_console_evtchn(void)
172{
173
174	return (legacy_start_info->console.domU.evtchn);
175}
176
177static uint32_t
178legacy_get_start_flags(void)
179{
180
181	return (legacy_start_info->flags);
182}
183
184struct hypervisor_info legacy_info = {
185	.get_xenstore_mfn		= legacy_get_xenstore_mfn,
186	.get_xenstore_evtchn		= legacy_get_xenstore_evtchn,
187	.get_console_mfn		= legacy_get_console_mfn,
188	.get_console_evtchn		= legacy_get_console_evtchn,
189	.get_start_flags		= legacy_get_start_flags,
190};
191
192/*-------------------------------- Xen PV init -------------------------------*/
193/*
194 * First function called by the Xen legacy PVH boot sequence.
195 *
196 * Set some Xen global variables and prepare the environment so it is
197 * as similar as possible to what native FreeBSD init function expects.
198 */
199uint64_t
200hammer_time_xen_legacy(start_info_t *si, uint64_t xenstack)
201{
202	uint64_t physfree;
203	uint64_t *PT4 = (u_int64_t *)xenstack;
204	uint64_t *PT3 = (u_int64_t *)(xenstack + PAGE_SIZE);
205	uint64_t *PT2 = (u_int64_t *)(xenstack + 2 * PAGE_SIZE);
206	int i;
207	char *kenv;
208
209	xen_domain_type = XEN_PV_DOMAIN;
210	vm_guest = VM_GUEST_XEN;
211
212	if ((si == NULL) || (xenstack == 0)) {
213		xc_printf("ERROR: invalid start_info or xen stack, halting\n");
214		HYPERVISOR_shutdown(SHUTDOWN_crash);
215	}
216
217	xc_printf("FreeBSD PVH running on %s\n", si->magic);
218
219	/* We use 3 pages of xen stack for the boot pagetables */
220	physfree = xenstack + 3 * PAGE_SIZE - KERNBASE;
221
222	/* Setup Xen global variables */
223	legacy_start_info = si;
224	HYPERVISOR_shared_info =
225	    (shared_info_t *)(si->shared_info + KERNBASE);
226
227	/*
228	 * Use the stack Xen gives us to build the page tables
229	 * as native FreeBSD expects to find them (created
230	 * by the boot trampoline).
231	 */
232	for (i = 0; i < (PAGE_SIZE / sizeof(uint64_t)); i++) {
233		/*
234		 * Each slot of the level 4 pages points
235		 * to the same level 3 page
236		 */
237		PT4[i] = ((uint64_t)&PT3[0]) - KERNBASE;
238		PT4[i] |= PG_V | PG_RW | PG_U;
239
240		/*
241		 * Each slot of the level 3 pages points
242		 * to the same level 2 page
243		 */
244		PT3[i] = ((uint64_t)&PT2[0]) - KERNBASE;
245		PT3[i] |= PG_V | PG_RW | PG_U;
246
247		/*
248		 * The level 2 page slots are mapped with
249		 * 2MB pages for 1GB.
250		 */
251		PT2[i] = i * (2 * 1024 * 1024);
252		PT2[i] |= PG_V | PG_RW | PG_PS | PG_U;
253	}
254	load_cr3(((uint64_t)&PT4[0]) - KERNBASE);
255
256	/*
257	 * Init an empty static kenv using a free page. The contents will be
258	 * filled from the parse_preload_data hook.
259	 */
260	kenv = (void *)(physfree + KERNBASE);
261	physfree += PAGE_SIZE;
262	bzero_early(kenv, PAGE_SIZE);
263	init_static_kenv(kenv, PAGE_SIZE);
264
265	/* Set the hooks for early functions that diverge from bare metal */
266	init_ops = xen_legacy_init_ops;
267	apic_ops = xen_apic_ops;
268	hypervisor_info = legacy_info;
269
270	/* Now we can jump into the native init function */
271	return (hammer_time(0, physfree));
272}
273
274uint64_t
275hammer_time_xen(vm_paddr_t start_info_paddr)
276{
277	struct hvm_modlist_entry *mod;
278	struct xen_add_to_physmap xatp;
279	uint64_t physfree;
280	char *kenv;
281	int rc;
282
283	xen_domain_type = XEN_HVM_DOMAIN;
284	vm_guest = VM_GUEST_XEN;
285
286	rc = xen_hvm_init_hypercall_stubs(XEN_HVM_INIT_EARLY);
287	if (rc) {
288		xc_printf("ERROR: failed to initialize hypercall page: %d\n",
289		    rc);
290		HYPERVISOR_shutdown(SHUTDOWN_crash);
291	}
292
293	start_info = (struct hvm_start_info *)(start_info_paddr + KERNBASE);
294	if (start_info->magic != XEN_HVM_START_MAGIC_VALUE) {
295		xc_printf("Unknown magic value in start_info struct: %#x\n",
296		    start_info->magic);
297		HYPERVISOR_shutdown(SHUTDOWN_crash);
298	}
299
300	/*
301	 * The hvm_start_into structure is always appended after loading
302	 * the kernel and modules.
303	 */
304	physfree = roundup2(start_info_paddr + PAGE_SIZE, PAGE_SIZE);
305
306	xatp.domid = DOMID_SELF;
307	xatp.idx = 0;
308	xatp.space = XENMAPSPACE_shared_info;
309	xatp.gpfn = atop(physfree);
310	if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) {
311		xc_printf("ERROR: failed to setup shared_info page\n");
312		HYPERVISOR_shutdown(SHUTDOWN_crash);
313	}
314	HYPERVISOR_shared_info = (shared_info_t *)(physfree + KERNBASE);
315	physfree += PAGE_SIZE;
316
317	/*
318	 * Init a static kenv using a free page. The contents will be filled
319	 * from the parse_preload_data hook.
320	 */
321	kenv = (void *)(physfree + KERNBASE);
322	physfree += PAGE_SIZE;
323	bzero_early(kenv, PAGE_SIZE);
324	init_static_kenv(kenv, PAGE_SIZE);
325
326	if (start_info->modlist_paddr != 0) {
327		if (start_info->modlist_paddr >= physfree) {
328			xc_printf(
329			    "ERROR: unexpected module list memory address\n");
330			HYPERVISOR_shutdown(SHUTDOWN_crash);
331		}
332		if (start_info->nr_modules == 0) {
333			xc_printf(
334			    "ERROR: modlist_paddr != 0 but nr_modules == 0\n");
335			HYPERVISOR_shutdown(SHUTDOWN_crash);
336		}
337		mod = (struct hvm_modlist_entry *)
338		    (vm_paddr_t)start_info->modlist_paddr + KERNBASE;
339		if (mod[0].paddr >= physfree) {
340			xc_printf("ERROR: unexpected module memory address\n");
341			HYPERVISOR_shutdown(SHUTDOWN_crash);
342		}
343	}
344
345	/* Set the hooks for early functions that diverge from bare metal */
346	init_ops = xen_pvh_init_ops;
347	hvm_start_flags = start_info->flags;
348
349	/* Now we can jump into the native init function */
350	return (hammer_time(0, physfree));
351}
352
353/*-------------------------------- PV specific -------------------------------*/
354#ifdef SMP
355static bool
356start_xen_ap(int cpu)
357{
358	struct vcpu_guest_context *ctxt;
359	int ms, cpus = mp_naps;
360	const size_t stacksize = kstack_pages * PAGE_SIZE;
361
362	/* allocate and set up an idle stack data page */
363	bootstacks[cpu] = (void *)kmem_malloc(stacksize, M_WAITOK | M_ZERO);
364	doublefault_stack = (char *)kmem_malloc(PAGE_SIZE, M_WAITOK | M_ZERO);
365	mce_stack = (char *)kmem_malloc(PAGE_SIZE, M_WAITOK | M_ZERO);
366	nmi_stack = (char *)kmem_malloc(PAGE_SIZE, M_WAITOK | M_ZERO);
367	dbg_stack = (void *)kmem_malloc(PAGE_SIZE, M_WAITOK | M_ZERO);
368	dpcpu = (void *)kmem_malloc(DPCPU_SIZE, M_WAITOK | M_ZERO);
369
370	bootSTK = (char *)bootstacks[cpu] + kstack_pages * PAGE_SIZE - 8;
371	bootAP = cpu;
372
373	ctxt = malloc(sizeof(*ctxt), M_TEMP, M_WAITOK | M_ZERO);
374
375	ctxt->flags = VGCF_IN_KERNEL;
376	ctxt->user_regs.rip = (unsigned long) init_secondary;
377	ctxt->user_regs.rsp = (unsigned long) bootSTK;
378
379	/* Set the AP to use the same page tables */
380	ctxt->ctrlreg[3] = KPML4phys;
381
382	if (HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, ctxt))
383		panic("unable to initialize AP#%d", cpu);
384
385	free(ctxt, M_TEMP);
386
387	/* Launch the vCPU */
388	if (HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL))
389		panic("unable to start AP#%d", cpu);
390
391	/* Wait up to 5 seconds for it to start. */
392	for (ms = 0; ms < 5000; ms++) {
393		if (mp_naps > cpus)
394			return (true);
395		DELAY(1000);
396	}
397
398	return (false);
399}
400
401static int
402xen_pv_start_all_aps(void)
403{
404	int cpu;
405
406	mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN);
407
408	for (cpu = 1; cpu < mp_ncpus; cpu++) {
409		/* attempt to start the Application Processor */
410		if (!start_xen_ap(cpu))
411			panic("AP #%d failed to start!", cpu);
412
413		CPU_SET(cpu, &all_cpus);	/* record AP in CPU map */
414	}
415
416	return (mp_naps);
417}
418#endif /* SMP */
419
420/*
421 * When booted as a PVH guest FreeBSD needs to avoid using the RSDP address
422 * hint provided by the loader because it points to the native set of ACPI
423 * tables instead of the ones crafted by Xen. The acpi.rsdp env variable is
424 * removed from kenv if present, and a new acpi.rsdp is added to kenv that
425 * points to the address of the Xen crafted RSDP.
426 */
427static bool reject_option(const char *option)
428{
429	static const char *reject[] = {
430		"acpi.rsdp",
431	};
432	unsigned int i;
433
434	for (i = 0; i < nitems(reject); i++)
435		if (strncmp(option, reject[i], strlen(reject[i])) == 0)
436			return (true);
437
438	return (false);
439}
440
441static void
442xen_pvh_set_env(char *env, bool (*filter)(const char *))
443{
444	char *option;
445
446	if (env == NULL)
447		return;
448
449	option = env;
450	while (*option != 0) {
451		char *value;
452
453		if (filter != NULL && filter(option)) {
454			option += strlen(option) + 1;
455			continue;
456		}
457
458		value = option;
459		option = strsep(&value, "=");
460		if (kern_setenv(option, value) != 0)
461			xc_printf("unable to add kenv %s=%s\n", option, value);
462		option = value + strlen(value) + 1;
463	}
464}
465
466#ifdef DDB
467/*
468 * The way Xen loads the symtab is different from the native boot loader,
469 * because it's tailored for NetBSD. So we have to adapt and use the same
470 * method as NetBSD. Portions of the code below have been picked from NetBSD:
471 * sys/kern/kern_ksyms.c CVS Revision 1.71.
472 */
473static void
474xen_pvh_parse_symtab(void)
475{
476	Elf_Ehdr *ehdr;
477	Elf_Shdr *shdr;
478	uint32_t size;
479	int i, j;
480
481	size = end;
482
483	ehdr = (Elf_Ehdr *)(&end + 1);
484	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) ||
485	    ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
486	    ehdr->e_version > 1) {
487		xc_printf("Unable to load ELF symtab: invalid symbol table\n");
488		return;
489	}
490
491	shdr = (Elf_Shdr *)((uint8_t *)ehdr + ehdr->e_shoff);
492	/* Find the symbol table and the corresponding string table. */
493	for (i = 1; i < ehdr->e_shnum; i++) {
494		if (shdr[i].sh_type != SHT_SYMTAB)
495			continue;
496		if (shdr[i].sh_offset == 0)
497			continue;
498		ksymtab = (uintptr_t)((uint8_t *)ehdr + shdr[i].sh_offset);
499		ksymtab_size = shdr[i].sh_size;
500		j = shdr[i].sh_link;
501		if (shdr[j].sh_offset == 0)
502			continue; /* Can this happen? */
503		kstrtab = (uintptr_t)((uint8_t *)ehdr + shdr[j].sh_offset);
504		break;
505	}
506
507	if (ksymtab == 0 || kstrtab == 0)
508		xc_printf(
509    "Unable to load ELF symtab: could not find symtab or strtab\n");
510}
511#endif
512
513static caddr_t
514xen_legacy_pvh_parse_preload_data(uint64_t modulep)
515{
516	caddr_t		 kmdp;
517	vm_ooffset_t	 off;
518	vm_paddr_t	 metadata;
519	char             *envp;
520
521	if (legacy_start_info->mod_start != 0) {
522		preload_metadata = (caddr_t)legacy_start_info->mod_start;
523
524		kmdp = preload_search_by_type("elf kernel");
525		if (kmdp == NULL)
526			kmdp = preload_search_by_type("elf64 kernel");
527		KASSERT(kmdp != NULL, ("unable to find kernel"));
528
529		/*
530		 * Xen has relocated the metadata and the modules,
531		 * so we need to recalculate it's position. This is
532		 * done by saving the original modulep address and
533		 * then calculating the offset with mod_start,
534		 * which contains the relocated modulep address.
535		 */
536		metadata = MD_FETCH(kmdp, MODINFOMD_MODULEP, vm_paddr_t);
537		off = legacy_start_info->mod_start - metadata;
538
539		preload_bootstrap_relocate(off);
540
541		boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
542		envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
543		if (envp != NULL)
544			envp += off;
545		xen_pvh_set_env(envp, NULL);
546	} else {
547		/* Parse the extra boot information given by Xen */
548		boot_parse_cmdline_delim(legacy_start_info->cmd_line, ",");
549		kmdp = NULL;
550	}
551
552	boothowto |= boot_env_to_howto();
553
554#ifdef DDB
555	xen_pvh_parse_symtab();
556#endif
557	return (kmdp);
558}
559
560static caddr_t
561xen_pvh_parse_preload_data(uint64_t modulep)
562{
563	caddr_t kmdp;
564	vm_ooffset_t off;
565	vm_paddr_t metadata;
566	char *envp;
567	char acpi_rsdp[19];
568
569	if (start_info->modlist_paddr != 0) {
570		struct hvm_modlist_entry *mod;
571		const char *cmdline;
572
573		mod = (struct hvm_modlist_entry *)
574		    (start_info->modlist_paddr + KERNBASE);
575		cmdline = mod[0].cmdline_paddr ?
576		    (const char *)(mod[0].cmdline_paddr + KERNBASE) : NULL;
577
578		if (strcmp(cmdline, "header") == 0) {
579			struct xen_header *header;
580
581			header = (struct xen_header *)(mod[0].paddr + KERNBASE);
582
583			if ((header->flags & XENHEADER_HAS_MODULEP_OFFSET) !=
584			    XENHEADER_HAS_MODULEP_OFFSET) {
585				xc_printf("Unable to load module metadata\n");
586				HYPERVISOR_shutdown(SHUTDOWN_crash);
587			}
588
589			preload_metadata = (caddr_t)(mod[0].paddr +
590			    header->modulep_offset + KERNBASE);
591
592			kmdp = preload_search_by_type("elf kernel");
593			if (kmdp == NULL)
594				kmdp = preload_search_by_type("elf64 kernel");
595			if (kmdp == NULL) {
596				xc_printf("Unable to find kernel\n");
597				HYPERVISOR_shutdown(SHUTDOWN_crash);
598			}
599
600			/*
601			 * Xen has relocated the metadata and the modules, so
602			 * we need to recalculate it's position. This is done
603			 * by saving the original modulep address and then
604			 * calculating the offset from the real modulep
605			 * position.
606			 */
607			metadata = MD_FETCH(kmdp, MODINFOMD_MODULEP,
608			    vm_paddr_t);
609			off = mod[0].paddr + header->modulep_offset - metadata +
610			    KERNBASE;
611		} else {
612			preload_metadata = (caddr_t)(mod[0].paddr + KERNBASE);
613
614			kmdp = preload_search_by_type("elf kernel");
615			if (kmdp == NULL)
616				kmdp = preload_search_by_type("elf64 kernel");
617			if (kmdp == NULL) {
618				xc_printf("Unable to find kernel\n");
619				HYPERVISOR_shutdown(SHUTDOWN_crash);
620			}
621
622			metadata = MD_FETCH(kmdp, MODINFOMD_MODULEP, vm_paddr_t);
623			off = mod[0].paddr + KERNBASE - metadata;
624		}
625
626		preload_bootstrap_relocate(off);
627
628		boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
629		envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
630		if (envp != NULL)
631			envp += off;
632		xen_pvh_set_env(envp, reject_option);
633	} else {
634		/* Parse the extra boot information given by Xen */
635		if (start_info->cmdline_paddr != 0)
636			boot_parse_cmdline_delim(
637			    (char *)(start_info->cmdline_paddr + KERNBASE),
638			    ",");
639		kmdp = NULL;
640	}
641
642	boothowto |= boot_env_to_howto();
643
644	snprintf(acpi_rsdp, sizeof(acpi_rsdp), "%#" PRIx64,
645	    start_info->rsdp_paddr);
646	kern_setenv("acpi.rsdp", acpi_rsdp);
647
648#ifdef DDB
649	xen_pvh_parse_symtab();
650#endif
651	return (kmdp);
652}
653
654static void
655xen_pvh_parse_memmap(caddr_t kmdp, vm_paddr_t *physmap, int *physmap_idx)
656{
657	struct xen_memory_map memmap;
658	u_int32_t size;
659	int rc;
660
661	/* Fetch the E820 map from Xen */
662	memmap.nr_entries = MAX_E820_ENTRIES;
663	set_xen_guest_handle(memmap.buffer, xen_smap);
664	rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap);
665	if (rc) {
666		xc_printf("ERROR: unable to fetch Xen E820 memory map: %d\n",
667		    rc);
668		HYPERVISOR_shutdown(SHUTDOWN_crash);
669	}
670
671	size = memmap.nr_entries * sizeof(xen_smap[0]);
672
673	bios_add_smap_entries(xen_smap, size, physmap, physmap_idx);
674}
675