xref: /freebsd/sys/x86/xen/pv.c (revision a2495c36678cb16597758ce150da5456cdd90331)
1ebf5747bSPedro F. Giffuni /*-
2ebf5747bSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-NetBSD
3ebf5747bSPedro F. Giffuni  *
41a9cdd37SRoger Pau Monné  * Copyright (c) 2004 Christian Limpach.
51a9cdd37SRoger Pau Monné  * Copyright (c) 2004-2006,2008 Kip Macy
69b4e54d3SRoger Pau Monné  * Copyright (c) 2008 The NetBSD Foundation, Inc.
71a9cdd37SRoger Pau Monné  * Copyright (c) 2013 Roger Pau Monné <roger.pau@citrix.com>
81a9cdd37SRoger Pau Monné  * All rights reserved.
91a9cdd37SRoger Pau Monné  *
101a9cdd37SRoger Pau Monné  * Redistribution and use in source and binary forms, with or without
111a9cdd37SRoger Pau Monné  * modification, are permitted provided that the following conditions
121a9cdd37SRoger Pau Monné  * are met:
131a9cdd37SRoger Pau Monné  * 1. Redistributions of source code must retain the above copyright
141a9cdd37SRoger Pau Monné  *    notice, this list of conditions and the following disclaimer.
151a9cdd37SRoger Pau Monné  * 2. Redistributions in binary form must reproduce the above copyright
161a9cdd37SRoger Pau Monné  *    notice, this list of conditions and the following disclaimer in the
171a9cdd37SRoger Pau Monné  *    documentation and/or other materials provided with the distribution.
181a9cdd37SRoger Pau Monné  *
191a9cdd37SRoger Pau Monné  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND
201a9cdd37SRoger Pau Monné  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
211a9cdd37SRoger Pau Monné  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
221a9cdd37SRoger Pau Monné  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
231a9cdd37SRoger Pau Monné  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
241a9cdd37SRoger Pau Monné  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
251a9cdd37SRoger Pau Monné  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
261a9cdd37SRoger Pau Monné  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
271a9cdd37SRoger Pau Monné  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
281a9cdd37SRoger Pau Monné  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
291a9cdd37SRoger Pau Monné  * SUCH DAMAGE.
301a9cdd37SRoger Pau Monné  */
311a9cdd37SRoger Pau Monné 
321a9cdd37SRoger Pau Monné #include <sys/cdefs.h>
331a9cdd37SRoger Pau Monné __FBSDID("$FreeBSD$");
341a9cdd37SRoger Pau Monné 
35c98a2727SRoger Pau Monné #include "opt_ddb.h"
36721555e7SZbigniew Bodek #include "opt_kstack_pages.h"
37c98a2727SRoger Pau Monné 
381a9cdd37SRoger Pau Monné #include <sys/param.h>
391a9cdd37SRoger Pau Monné #include <sys/bus.h>
401a9cdd37SRoger Pau Monné #include <sys/kernel.h>
411a9cdd37SRoger Pau Monné #include <sys/reboot.h>
421a9cdd37SRoger Pau Monné #include <sys/systm.h>
43079f7ef8SRoger Pau Monné #include <sys/malloc.h>
44c98a2727SRoger Pau Monné #include <sys/linker.h>
451a9cdd37SRoger Pau Monné #include <sys/lock.h>
461a9cdd37SRoger Pau Monné #include <sys/rwlock.h>
47aa389b4fSRoger Pau Monné #include <sys/boot.h>
4897baeefdSRoger Pau Monné #include <sys/ctype.h>
49079f7ef8SRoger Pau Monné #include <sys/mutex.h>
50079f7ef8SRoger Pau Monné #include <sys/smp.h>
51*a2495c36SRoger Pau Monné #include <sys/efi.h>
521a9cdd37SRoger Pau Monné 
531a9cdd37SRoger Pau Monné #include <vm/vm.h>
541a9cdd37SRoger Pau Monné #include <vm/vm_extern.h>
551a9cdd37SRoger Pau Monné #include <vm/vm_kern.h>
561a9cdd37SRoger Pau Monné #include <vm/vm_page.h>
571a9cdd37SRoger Pau Monné #include <vm/vm_map.h>
581a9cdd37SRoger Pau Monné #include <vm/vm_object.h>
591a9cdd37SRoger Pau Monné #include <vm/vm_pager.h>
601a9cdd37SRoger Pau Monné #include <vm/vm_param.h>
611a9cdd37SRoger Pau Monné 
62b0663c33SRoger Pau Monné #include <machine/_inttypes.h>
63fae92773SJohn Baldwin #include <machine/intr_machdep.h>
64fae92773SJohn Baldwin #include <x86/apicvar.h>
6597baeefdSRoger Pau Monné #include <x86/init.h>
661e69553eSRoger Pau Monné #include <machine/pc/bios.h>
67079f7ef8SRoger Pau Monné #include <machine/smp.h>
6844e06d15SRoger Pau Monné #include <machine/intr_machdep.h>
69*a2495c36SRoger Pau Monné #include <machine/md_var.h>
70ca49b334SRoger Pau Monné #include <machine/metadata.h>
7197baeefdSRoger Pau Monné 
721a9cdd37SRoger Pau Monné #include <xen/xen-os.h>
73b0663c33SRoger Pau Monné #include <xen/hvm.h>
741a9cdd37SRoger Pau Monné #include <xen/hypervisor.h>
75b7df74eeSWarner Losh #include <xen/xenstore/xenstorevar.h>
76842471b3SRoger Pau Monné #include <xen/xen_pv.h>
7744e06d15SRoger Pau Monné #include <xen/xen_msi.h>
781a9cdd37SRoger Pau Monné 
79b0663c33SRoger Pau Monné #include <xen/interface/arch-x86/hvm/start_info.h>
80079f7ef8SRoger Pau Monné #include <xen/interface/vcpu.h>
81079f7ef8SRoger Pau Monné 
825f05c794SRoger Pau Monné #include <dev/xen/timer/timer.h>
835f05c794SRoger Pau Monné 
84c98a2727SRoger Pau Monné #ifdef DDB
85c98a2727SRoger Pau Monné #include <ddb/ddb.h>
86c98a2727SRoger Pau Monné #endif
87c98a2727SRoger Pau Monné 
881a9cdd37SRoger Pau Monné /* Native initial function */
891a9cdd37SRoger Pau Monné extern u_int64_t hammer_time(u_int64_t, u_int64_t);
901a9cdd37SRoger Pau Monné /* Xen initial function */
91b0663c33SRoger Pau Monné uint64_t hammer_time_xen_legacy(start_info_t *, uint64_t);
92b0663c33SRoger Pau Monné uint64_t hammer_time_xen(vm_paddr_t);
931a9cdd37SRoger Pau Monné 
941e69553eSRoger Pau Monné #define MAX_E820_ENTRIES	128
951e69553eSRoger Pau Monné 
9697baeefdSRoger Pau Monné /*--------------------------- Forward Declarations ---------------------------*/
97b0663c33SRoger Pau Monné static caddr_t xen_legacy_pvh_parse_preload_data(uint64_t);
98b0663c33SRoger Pau Monné static caddr_t xen_pvh_parse_preload_data(uint64_t);
99b0663c33SRoger Pau Monné static void xen_pvh_parse_memmap(caddr_t, vm_paddr_t *, int *);
10097baeefdSRoger Pau Monné 
101079f7ef8SRoger Pau Monné #ifdef SMP
102079f7ef8SRoger Pau Monné static int xen_pv_start_all_aps(void);
103079f7ef8SRoger Pau Monné #endif
104079f7ef8SRoger Pau Monné 
105079f7ef8SRoger Pau Monné /*---------------------------- Extern Declarations ---------------------------*/
106079f7ef8SRoger Pau Monné #ifdef SMP
107079f7ef8SRoger Pau Monné /* Variables used by amd64 mp_machdep to start APs */
108079f7ef8SRoger Pau Monné extern char *doublefault_stack;
109b345111bSMateusz Guzik extern char *mce_stack;
110079f7ef8SRoger Pau Monné extern char *nmi_stack;
11192849603SRoger Pau Monné extern char *dbg_stack;
112079f7ef8SRoger Pau Monné #endif
113079f7ef8SRoger Pau Monné 
114c98a2727SRoger Pau Monné /*
115c98a2727SRoger Pau Monné  * Placed by the linker at the end of the bss section, which is the last
116c98a2727SRoger Pau Monné  * section loaded by Xen before loading the symtab and strtab.
117c98a2727SRoger Pau Monné  */
118c98a2727SRoger Pau Monné extern uint32_t end;
119c98a2727SRoger Pau Monné 
12097baeefdSRoger Pau Monné /*-------------------------------- Global Data -------------------------------*/
12197baeefdSRoger Pau Monné /* Xen init_ops implementation. */
122b0663c33SRoger Pau Monné struct init_ops xen_legacy_init_ops = {
123b0663c33SRoger Pau Monné 	.parse_preload_data		= xen_legacy_pvh_parse_preload_data,
1245f05c794SRoger Pau Monné 	.early_clock_source_init	= xen_clock_init,
1255f05c794SRoger Pau Monné 	.early_delay			= xen_delay,
126b0663c33SRoger Pau Monné 	.parse_memmap			= xen_pvh_parse_memmap,
127079f7ef8SRoger Pau Monné #ifdef SMP
128079f7ef8SRoger Pau Monné 	.start_all_aps			= xen_pv_start_all_aps,
129079f7ef8SRoger Pau Monné #endif
13044e06d15SRoger Pau Monné 	.msi_init			= xen_msi_init,
13197baeefdSRoger Pau Monné };
13297baeefdSRoger Pau Monné 
133b0663c33SRoger Pau Monné struct init_ops xen_pvh_init_ops = {
134b0663c33SRoger Pau Monné 	.parse_preload_data		= xen_pvh_parse_preload_data,
135b0663c33SRoger Pau Monné 	.early_clock_source_init	= xen_clock_init,
136b0663c33SRoger Pau Monné 	.early_delay			= xen_delay,
137b0663c33SRoger Pau Monné 	.parse_memmap			= xen_pvh_parse_memmap,
138b0663c33SRoger Pau Monné #ifdef SMP
139b0663c33SRoger Pau Monné 	.mp_bootaddress			= mp_bootaddress,
140b0663c33SRoger Pau Monné 	.start_all_aps			= native_start_all_aps,
141b0663c33SRoger Pau Monné #endif
142b0663c33SRoger Pau Monné 	.msi_init			= msi_init,
143b0663c33SRoger Pau Monné };
144b0663c33SRoger Pau Monné 
1451e69553eSRoger Pau Monné static struct bios_smap xen_smap[MAX_E820_ENTRIES];
1461e69553eSRoger Pau Monné 
147cfa0b7b8SRoger Pau Monné static start_info_t *legacy_start_info;
148b0663c33SRoger Pau Monné static struct hvm_start_info *start_info;
149cfa0b7b8SRoger Pau Monné 
150cfa0b7b8SRoger Pau Monné /*----------------------- Legacy PVH start_info accessors --------------------*/
151cfa0b7b8SRoger Pau Monné static vm_paddr_t
152cfa0b7b8SRoger Pau Monné legacy_get_xenstore_mfn(void)
153cfa0b7b8SRoger Pau Monné {
154cfa0b7b8SRoger Pau Monné 
155cfa0b7b8SRoger Pau Monné 	return (legacy_start_info->store_mfn);
156cfa0b7b8SRoger Pau Monné }
157cfa0b7b8SRoger Pau Monné 
158cfa0b7b8SRoger Pau Monné static evtchn_port_t
159cfa0b7b8SRoger Pau Monné legacy_get_xenstore_evtchn(void)
160cfa0b7b8SRoger Pau Monné {
161cfa0b7b8SRoger Pau Monné 
162cfa0b7b8SRoger Pau Monné 	return (legacy_start_info->store_evtchn);
163cfa0b7b8SRoger Pau Monné }
164cfa0b7b8SRoger Pau Monné 
165cfa0b7b8SRoger Pau Monné static vm_paddr_t
166cfa0b7b8SRoger Pau Monné legacy_get_console_mfn(void)
167cfa0b7b8SRoger Pau Monné {
168cfa0b7b8SRoger Pau Monné 
169cfa0b7b8SRoger Pau Monné 	return (legacy_start_info->console.domU.mfn);
170cfa0b7b8SRoger Pau Monné }
171cfa0b7b8SRoger Pau Monné 
172cfa0b7b8SRoger Pau Monné static evtchn_port_t
173cfa0b7b8SRoger Pau Monné legacy_get_console_evtchn(void)
174cfa0b7b8SRoger Pau Monné {
175cfa0b7b8SRoger Pau Monné 
176cfa0b7b8SRoger Pau Monné 	return (legacy_start_info->console.domU.evtchn);
177cfa0b7b8SRoger Pau Monné }
178cfa0b7b8SRoger Pau Monné 
179cfa0b7b8SRoger Pau Monné static uint32_t
180cfa0b7b8SRoger Pau Monné legacy_get_start_flags(void)
181cfa0b7b8SRoger Pau Monné {
182cfa0b7b8SRoger Pau Monné 
183cfa0b7b8SRoger Pau Monné 	return (legacy_start_info->flags);
184cfa0b7b8SRoger Pau Monné }
185cfa0b7b8SRoger Pau Monné 
186cfa0b7b8SRoger Pau Monné struct hypervisor_info legacy_info = {
187cfa0b7b8SRoger Pau Monné 	.get_xenstore_mfn		= legacy_get_xenstore_mfn,
188cfa0b7b8SRoger Pau Monné 	.get_xenstore_evtchn		= legacy_get_xenstore_evtchn,
189cfa0b7b8SRoger Pau Monné 	.get_console_mfn		= legacy_get_console_mfn,
190cfa0b7b8SRoger Pau Monné 	.get_console_evtchn		= legacy_get_console_evtchn,
191cfa0b7b8SRoger Pau Monné 	.get_start_flags		= legacy_get_start_flags,
192cfa0b7b8SRoger Pau Monné };
193cfa0b7b8SRoger Pau Monné 
19497baeefdSRoger Pau Monné /*-------------------------------- Xen PV init -------------------------------*/
1951a9cdd37SRoger Pau Monné /*
196cfa0b7b8SRoger Pau Monné  * First function called by the Xen legacy PVH boot sequence.
1971a9cdd37SRoger Pau Monné  *
1981a9cdd37SRoger Pau Monné  * Set some Xen global variables and prepare the environment so it is
1991a9cdd37SRoger Pau Monné  * as similar as possible to what native FreeBSD init function expects.
2001a9cdd37SRoger Pau Monné  */
2011a9cdd37SRoger Pau Monné uint64_t
202b0663c33SRoger Pau Monné hammer_time_xen_legacy(start_info_t *si, uint64_t xenstack)
2031a9cdd37SRoger Pau Monné {
2041a9cdd37SRoger Pau Monné 	uint64_t physfree;
2051a9cdd37SRoger Pau Monné 	uint64_t *PT4 = (u_int64_t *)xenstack;
2061a9cdd37SRoger Pau Monné 	uint64_t *PT3 = (u_int64_t *)(xenstack + PAGE_SIZE);
2071a9cdd37SRoger Pau Monné 	uint64_t *PT2 = (u_int64_t *)(xenstack + 2 * PAGE_SIZE);
2081a9cdd37SRoger Pau Monné 	int i;
209ddbc1b43SRoger Pau Monné 	char *kenv;
2101a9cdd37SRoger Pau Monné 
2111a9cdd37SRoger Pau Monné 	xen_domain_type = XEN_PV_DOMAIN;
2121a9cdd37SRoger Pau Monné 	vm_guest = VM_GUEST_XEN;
2131a9cdd37SRoger Pau Monné 
2141a9cdd37SRoger Pau Monné 	if ((si == NULL) || (xenstack == 0)) {
215c203fa69SRoger Pau Monné 		xc_printf("ERROR: invalid start_info or xen stack, halting\n");
2161a9cdd37SRoger Pau Monné 		HYPERVISOR_shutdown(SHUTDOWN_crash);
2171a9cdd37SRoger Pau Monné 	}
2181a9cdd37SRoger Pau Monné 
219c203fa69SRoger Pau Monné 	xc_printf("FreeBSD PVH running on %s\n", si->magic);
220c203fa69SRoger Pau Monné 
2211a9cdd37SRoger Pau Monné 	/* We use 3 pages of xen stack for the boot pagetables */
2221a9cdd37SRoger Pau Monné 	physfree = xenstack + 3 * PAGE_SIZE - KERNBASE;
2231a9cdd37SRoger Pau Monné 
2241a9cdd37SRoger Pau Monné 	/* Setup Xen global variables */
225cfa0b7b8SRoger Pau Monné 	legacy_start_info = si;
2261a9cdd37SRoger Pau Monné 	HYPERVISOR_shared_info =
2271a9cdd37SRoger Pau Monné 	    (shared_info_t *)(si->shared_info + KERNBASE);
2281a9cdd37SRoger Pau Monné 
2291a9cdd37SRoger Pau Monné 	/*
2301a9cdd37SRoger Pau Monné 	 * Use the stack Xen gives us to build the page tables
2311a9cdd37SRoger Pau Monné 	 * as native FreeBSD expects to find them (created
2321a9cdd37SRoger Pau Monné 	 * by the boot trampoline).
2331a9cdd37SRoger Pau Monné 	 */
2341a9cdd37SRoger Pau Monné 	for (i = 0; i < (PAGE_SIZE / sizeof(uint64_t)); i++) {
2355f35f84fSRoger Pau Monné 		/*
2365f35f84fSRoger Pau Monné 		 * Each slot of the level 4 pages points
2375f35f84fSRoger Pau Monné 		 * to the same level 3 page
2385f35f84fSRoger Pau Monné 		 */
2391a9cdd37SRoger Pau Monné 		PT4[i] = ((uint64_t)&PT3[0]) - KERNBASE;
2401a9cdd37SRoger Pau Monné 		PT4[i] |= PG_V | PG_RW | PG_U;
2411a9cdd37SRoger Pau Monné 
2425f35f84fSRoger Pau Monné 		/*
2435f35f84fSRoger Pau Monné 		 * Each slot of the level 3 pages points
2445f35f84fSRoger Pau Monné 		 * to the same level 2 page
2455f35f84fSRoger Pau Monné 		 */
2461a9cdd37SRoger Pau Monné 		PT3[i] = ((uint64_t)&PT2[0]) - KERNBASE;
2471a9cdd37SRoger Pau Monné 		PT3[i] |= PG_V | PG_RW | PG_U;
2481a9cdd37SRoger Pau Monné 
2495f35f84fSRoger Pau Monné 		/*
2505f35f84fSRoger Pau Monné 		 * The level 2 page slots are mapped with
2515f35f84fSRoger Pau Monné 		 * 2MB pages for 1GB.
2525f35f84fSRoger Pau Monné 		 */
2531a9cdd37SRoger Pau Monné 		PT2[i] = i * (2 * 1024 * 1024);
2541a9cdd37SRoger Pau Monné 		PT2[i] |= PG_V | PG_RW | PG_PS | PG_U;
2551a9cdd37SRoger Pau Monné 	}
2561a9cdd37SRoger Pau Monné 	load_cr3(((uint64_t)&PT4[0]) - KERNBASE);
2571a9cdd37SRoger Pau Monné 
258ddbc1b43SRoger Pau Monné 	/*
259ddbc1b43SRoger Pau Monné 	 * Init an empty static kenv using a free page. The contents will be
260ddbc1b43SRoger Pau Monné 	 * filled from the parse_preload_data hook.
261ddbc1b43SRoger Pau Monné 	 */
262ddbc1b43SRoger Pau Monné 	kenv = (void *)(physfree + KERNBASE);
263ddbc1b43SRoger Pau Monné 	physfree += PAGE_SIZE;
2643f102f58SMateusz Guzik 	bzero_early(kenv, PAGE_SIZE);
265ddbc1b43SRoger Pau Monné 	init_static_kenv(kenv, PAGE_SIZE);
266ddbc1b43SRoger Pau Monné 
26797baeefdSRoger Pau Monné 	/* Set the hooks for early functions that diverge from bare metal */
268b0663c33SRoger Pau Monné 	init_ops = xen_legacy_init_ops;
269842471b3SRoger Pau Monné 	apic_ops = xen_apic_ops;
270cfa0b7b8SRoger Pau Monné 	hypervisor_info = legacy_info;
27197baeefdSRoger Pau Monné 
2721a9cdd37SRoger Pau Monné 	/* Now we can jump into the native init function */
2731a9cdd37SRoger Pau Monné 	return (hammer_time(0, physfree));
2741a9cdd37SRoger Pau Monné }
27597baeefdSRoger Pau Monné 
276b0663c33SRoger Pau Monné uint64_t
277b0663c33SRoger Pau Monné hammer_time_xen(vm_paddr_t start_info_paddr)
278b0663c33SRoger Pau Monné {
279b0663c33SRoger Pau Monné 	struct hvm_modlist_entry *mod;
280b0663c33SRoger Pau Monné 	struct xen_add_to_physmap xatp;
281b0663c33SRoger Pau Monné 	uint64_t physfree;
282b0663c33SRoger Pau Monné 	char *kenv;
283b0663c33SRoger Pau Monné 	int rc;
284b0663c33SRoger Pau Monné 
285b0663c33SRoger Pau Monné 	xen_domain_type = XEN_HVM_DOMAIN;
286b0663c33SRoger Pau Monné 	vm_guest = VM_GUEST_XEN;
287b0663c33SRoger Pau Monné 
288b0663c33SRoger Pau Monné 	rc = xen_hvm_init_hypercall_stubs(XEN_HVM_INIT_EARLY);
289b0663c33SRoger Pau Monné 	if (rc) {
290b0663c33SRoger Pau Monné 		xc_printf("ERROR: failed to initialize hypercall page: %d\n",
291b0663c33SRoger Pau Monné 		    rc);
292b0663c33SRoger Pau Monné 		HYPERVISOR_shutdown(SHUTDOWN_crash);
293b0663c33SRoger Pau Monné 	}
294b0663c33SRoger Pau Monné 
295b0663c33SRoger Pau Monné 	start_info = (struct hvm_start_info *)(start_info_paddr + KERNBASE);
296b0663c33SRoger Pau Monné 	if (start_info->magic != XEN_HVM_START_MAGIC_VALUE) {
297b0663c33SRoger Pau Monné 		xc_printf("Unknown magic value in start_info struct: %#x\n",
298b0663c33SRoger Pau Monné 		    start_info->magic);
299b0663c33SRoger Pau Monné 		HYPERVISOR_shutdown(SHUTDOWN_crash);
300b0663c33SRoger Pau Monné 	}
301b0663c33SRoger Pau Monné 
302b0663c33SRoger Pau Monné 	/*
303b0663c33SRoger Pau Monné 	 * The hvm_start_into structure is always appended after loading
304b0663c33SRoger Pau Monné 	 * the kernel and modules.
305b0663c33SRoger Pau Monné 	 */
306b0663c33SRoger Pau Monné 	physfree = roundup2(start_info_paddr + PAGE_SIZE, PAGE_SIZE);
307b0663c33SRoger Pau Monné 
308b0663c33SRoger Pau Monné 	xatp.domid = DOMID_SELF;
309b0663c33SRoger Pau Monné 	xatp.idx = 0;
310b0663c33SRoger Pau Monné 	xatp.space = XENMAPSPACE_shared_info;
311b0663c33SRoger Pau Monné 	xatp.gpfn = atop(physfree);
312b0663c33SRoger Pau Monné 	if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) {
313b0663c33SRoger Pau Monné 		xc_printf("ERROR: failed to setup shared_info page\n");
314b0663c33SRoger Pau Monné 		HYPERVISOR_shutdown(SHUTDOWN_crash);
315b0663c33SRoger Pau Monné 	}
316b0663c33SRoger Pau Monné 	HYPERVISOR_shared_info = (shared_info_t *)(physfree + KERNBASE);
317b0663c33SRoger Pau Monné 	physfree += PAGE_SIZE;
318b0663c33SRoger Pau Monné 
319b0663c33SRoger Pau Monné 	/*
320b0663c33SRoger Pau Monné 	 * Init a static kenv using a free page. The contents will be filled
321b0663c33SRoger Pau Monné 	 * from the parse_preload_data hook.
322b0663c33SRoger Pau Monné 	 */
323b0663c33SRoger Pau Monné 	kenv = (void *)(physfree + KERNBASE);
324b0663c33SRoger Pau Monné 	physfree += PAGE_SIZE;
3253f102f58SMateusz Guzik 	bzero_early(kenv, PAGE_SIZE);
326b0663c33SRoger Pau Monné 	init_static_kenv(kenv, PAGE_SIZE);
327b0663c33SRoger Pau Monné 
328b0663c33SRoger Pau Monné 	if (start_info->modlist_paddr != 0) {
329b0663c33SRoger Pau Monné 		if (start_info->modlist_paddr >= physfree) {
330b0663c33SRoger Pau Monné 			xc_printf(
331b0663c33SRoger Pau Monné 			    "ERROR: unexpected module list memory address\n");
332b0663c33SRoger Pau Monné 			HYPERVISOR_shutdown(SHUTDOWN_crash);
333b0663c33SRoger Pau Monné 		}
334b0663c33SRoger Pau Monné 		if (start_info->nr_modules == 0) {
335b0663c33SRoger Pau Monné 			xc_printf(
336b0663c33SRoger Pau Monné 			    "ERROR: modlist_paddr != 0 but nr_modules == 0\n");
337b0663c33SRoger Pau Monné 			HYPERVISOR_shutdown(SHUTDOWN_crash);
338b0663c33SRoger Pau Monné 		}
339b0663c33SRoger Pau Monné 		mod = (struct hvm_modlist_entry *)
340b0663c33SRoger Pau Monné 		    (vm_paddr_t)start_info->modlist_paddr + KERNBASE;
341b0663c33SRoger Pau Monné 		if (mod[0].paddr >= physfree) {
342b0663c33SRoger Pau Monné 			xc_printf("ERROR: unexpected module memory address\n");
343b0663c33SRoger Pau Monné 			HYPERVISOR_shutdown(SHUTDOWN_crash);
344b0663c33SRoger Pau Monné 		}
345b0663c33SRoger Pau Monné 	}
346b0663c33SRoger Pau Monné 
347b0663c33SRoger Pau Monné 	/* Set the hooks for early functions that diverge from bare metal */
348b0663c33SRoger Pau Monné 	init_ops = xen_pvh_init_ops;
349b0663c33SRoger Pau Monné 	hvm_start_flags = start_info->flags;
350b0663c33SRoger Pau Monné 
351b0663c33SRoger Pau Monné 	/* Now we can jump into the native init function */
352b0663c33SRoger Pau Monné 	return (hammer_time(0, physfree));
353b0663c33SRoger Pau Monné }
354b0663c33SRoger Pau Monné 
35597baeefdSRoger Pau Monné /*-------------------------------- PV specific -------------------------------*/
356079f7ef8SRoger Pau Monné #ifdef SMP
357079f7ef8SRoger Pau Monné static bool
358079f7ef8SRoger Pau Monné start_xen_ap(int cpu)
359079f7ef8SRoger Pau Monné {
360079f7ef8SRoger Pau Monné 	struct vcpu_guest_context *ctxt;
361079f7ef8SRoger Pau Monné 	int ms, cpus = mp_naps;
362edc82223SKonstantin Belousov 	const size_t stacksize = kstack_pages * PAGE_SIZE;
363079f7ef8SRoger Pau Monné 
364079f7ef8SRoger Pau Monné 	/* allocate and set up an idle stack data page */
36583a90bffSAlan Cox 	bootstacks[cpu] = (void *)kmem_malloc(stacksize, M_WAITOK | M_ZERO);
36683a90bffSAlan Cox 	doublefault_stack = (char *)kmem_malloc(PAGE_SIZE, M_WAITOK | M_ZERO);
36783a90bffSAlan Cox 	mce_stack = (char *)kmem_malloc(PAGE_SIZE, M_WAITOK | M_ZERO);
36883a90bffSAlan Cox 	nmi_stack = (char *)kmem_malloc(PAGE_SIZE, M_WAITOK | M_ZERO);
36983a90bffSAlan Cox 	dbg_stack = (void *)kmem_malloc(PAGE_SIZE, M_WAITOK | M_ZERO);
37083a90bffSAlan Cox 	dpcpu = (void *)kmem_malloc(DPCPU_SIZE, M_WAITOK | M_ZERO);
371079f7ef8SRoger Pau Monné 
372edc82223SKonstantin Belousov 	bootSTK = (char *)bootstacks[cpu] + kstack_pages * PAGE_SIZE - 8;
373079f7ef8SRoger Pau Monné 	bootAP = cpu;
374079f7ef8SRoger Pau Monné 
375079f7ef8SRoger Pau Monné 	ctxt = malloc(sizeof(*ctxt), M_TEMP, M_WAITOK | M_ZERO);
376079f7ef8SRoger Pau Monné 
377079f7ef8SRoger Pau Monné 	ctxt->flags = VGCF_IN_KERNEL;
378079f7ef8SRoger Pau Monné 	ctxt->user_regs.rip = (unsigned long) init_secondary;
379079f7ef8SRoger Pau Monné 	ctxt->user_regs.rsp = (unsigned long) bootSTK;
380079f7ef8SRoger Pau Monné 
381079f7ef8SRoger Pau Monné 	/* Set the AP to use the same page tables */
382079f7ef8SRoger Pau Monné 	ctxt->ctrlreg[3] = KPML4phys;
383079f7ef8SRoger Pau Monné 
384079f7ef8SRoger Pau Monné 	if (HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, ctxt))
385079f7ef8SRoger Pau Monné 		panic("unable to initialize AP#%d", cpu);
386079f7ef8SRoger Pau Monné 
387079f7ef8SRoger Pau Monné 	free(ctxt, M_TEMP);
388079f7ef8SRoger Pau Monné 
389079f7ef8SRoger Pau Monné 	/* Launch the vCPU */
390079f7ef8SRoger Pau Monné 	if (HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL))
391079f7ef8SRoger Pau Monné 		panic("unable to start AP#%d", cpu);
392079f7ef8SRoger Pau Monné 
393079f7ef8SRoger Pau Monné 	/* Wait up to 5 seconds for it to start. */
394079f7ef8SRoger Pau Monné 	for (ms = 0; ms < 5000; ms++) {
395079f7ef8SRoger Pau Monné 		if (mp_naps > cpus)
396079f7ef8SRoger Pau Monné 			return (true);
397079f7ef8SRoger Pau Monné 		DELAY(1000);
398079f7ef8SRoger Pau Monné 	}
399079f7ef8SRoger Pau Monné 
400079f7ef8SRoger Pau Monné 	return (false);
401079f7ef8SRoger Pau Monné }
402079f7ef8SRoger Pau Monné 
403079f7ef8SRoger Pau Monné static int
404079f7ef8SRoger Pau Monné xen_pv_start_all_aps(void)
405079f7ef8SRoger Pau Monné {
406079f7ef8SRoger Pau Monné 	int cpu;
407079f7ef8SRoger Pau Monné 
408079f7ef8SRoger Pau Monné 	mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN);
409079f7ef8SRoger Pau Monné 
410079f7ef8SRoger Pau Monné 	for (cpu = 1; cpu < mp_ncpus; cpu++) {
411079f7ef8SRoger Pau Monné 		/* attempt to start the Application Processor */
412079f7ef8SRoger Pau Monné 		if (!start_xen_ap(cpu))
413079f7ef8SRoger Pau Monné 			panic("AP #%d failed to start!", cpu);
414079f7ef8SRoger Pau Monné 
415079f7ef8SRoger Pau Monné 		CPU_SET(cpu, &all_cpus);	/* record AP in CPU map */
416079f7ef8SRoger Pau Monné 	}
417079f7ef8SRoger Pau Monné 
418079f7ef8SRoger Pau Monné 	return (mp_naps);
419079f7ef8SRoger Pau Monné }
420079f7ef8SRoger Pau Monné #endif /* SMP */
421079f7ef8SRoger Pau Monné 
42297baeefdSRoger Pau Monné /*
423b0663c33SRoger Pau Monné  * When booted as a PVH guest FreeBSD needs to avoid using the RSDP address
424b0663c33SRoger Pau Monné  * hint provided by the loader because it points to the native set of ACPI
425b0663c33SRoger Pau Monné  * tables instead of the ones crafted by Xen. The acpi.rsdp env variable is
426b0663c33SRoger Pau Monné  * removed from kenv if present, and a new acpi.rsdp is added to kenv that
427b0663c33SRoger Pau Monné  * points to the address of the Xen crafted RSDP.
42897baeefdSRoger Pau Monné  */
429b0663c33SRoger Pau Monné static bool reject_option(const char *option)
43097baeefdSRoger Pau Monné {
431b0663c33SRoger Pau Monné 	static const char *reject[] = {
432b0663c33SRoger Pau Monné 		"acpi.rsdp",
433b0663c33SRoger Pau Monné 	};
434b0663c33SRoger Pau Monné 	unsigned int i;
43597baeefdSRoger Pau Monné 
436b0663c33SRoger Pau Monné 	for (i = 0; i < nitems(reject); i++)
437b0663c33SRoger Pau Monné 		if (strncmp(option, reject[i], strlen(reject[i])) == 0)
438b0663c33SRoger Pau Monné 			return (true);
43997baeefdSRoger Pau Monné 
440b0663c33SRoger Pau Monné 	return (false);
441b0663c33SRoger Pau Monné }
44297baeefdSRoger Pau Monné 
443b0663c33SRoger Pau Monné static void
444b0663c33SRoger Pau Monné xen_pvh_set_env(char *env, bool (*filter)(const char *))
445b0663c33SRoger Pau Monné {
446b0663c33SRoger Pau Monné 	char *option;
44797baeefdSRoger Pau Monné 
448b0663c33SRoger Pau Monné 	if (env == NULL)
449b0663c33SRoger Pau Monné 		return;
450b0663c33SRoger Pau Monné 
451b0663c33SRoger Pau Monné 	option = env;
452b0663c33SRoger Pau Monné 	while (*option != 0) {
453b0663c33SRoger Pau Monné 		char *value;
454b0663c33SRoger Pau Monné 
455b0663c33SRoger Pau Monné 		if (filter != NULL && filter(option)) {
456b0663c33SRoger Pau Monné 			option += strlen(option) + 1;
457b0663c33SRoger Pau Monné 			continue;
458b0663c33SRoger Pau Monné 		}
459b0663c33SRoger Pau Monné 
460b0663c33SRoger Pau Monné 		value = option;
461b0663c33SRoger Pau Monné 		option = strsep(&value, "=");
462b0663c33SRoger Pau Monné 		if (kern_setenv(option, value) != 0)
463b0663c33SRoger Pau Monné 			xc_printf("unable to add kenv %s=%s\n", option, value);
464b0663c33SRoger Pau Monné 		option = value + strlen(value) + 1;
465b0663c33SRoger Pau Monné 	}
46697baeefdSRoger Pau Monné }
46797baeefdSRoger Pau Monné 
468c98a2727SRoger Pau Monné #ifdef DDB
469c98a2727SRoger Pau Monné /*
470c98a2727SRoger Pau Monné  * The way Xen loads the symtab is different from the native boot loader,
471c98a2727SRoger Pau Monné  * because it's tailored for NetBSD. So we have to adapt and use the same
472c98a2727SRoger Pau Monné  * method as NetBSD. Portions of the code below have been picked from NetBSD:
473c98a2727SRoger Pau Monné  * sys/kern/kern_ksyms.c CVS Revision 1.71.
474c98a2727SRoger Pau Monné  */
475c98a2727SRoger Pau Monné static void
476b0663c33SRoger Pau Monné xen_pvh_parse_symtab(void)
477c98a2727SRoger Pau Monné {
478c98a2727SRoger Pau Monné 	Elf_Ehdr *ehdr;
479c98a2727SRoger Pau Monné 	Elf_Shdr *shdr;
480c98a2727SRoger Pau Monné 	uint32_t size;
481c98a2727SRoger Pau Monné 	int i, j;
482c98a2727SRoger Pau Monné 
483c98a2727SRoger Pau Monné 	size = end;
484c98a2727SRoger Pau Monné 
485c98a2727SRoger Pau Monné 	ehdr = (Elf_Ehdr *)(&end + 1);
486c98a2727SRoger Pau Monné 	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) ||
487c98a2727SRoger Pau Monné 	    ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
488c98a2727SRoger Pau Monné 	    ehdr->e_version > 1) {
489c98a2727SRoger Pau Monné 		xc_printf("Unable to load ELF symtab: invalid symbol table\n");
490c98a2727SRoger Pau Monné 		return;
491c98a2727SRoger Pau Monné 	}
492c98a2727SRoger Pau Monné 
493c98a2727SRoger Pau Monné 	shdr = (Elf_Shdr *)((uint8_t *)ehdr + ehdr->e_shoff);
494c98a2727SRoger Pau Monné 	/* Find the symbol table and the corresponding string table. */
495c98a2727SRoger Pau Monné 	for (i = 1; i < ehdr->e_shnum; i++) {
496c98a2727SRoger Pau Monné 		if (shdr[i].sh_type != SHT_SYMTAB)
497c98a2727SRoger Pau Monné 			continue;
498c98a2727SRoger Pau Monné 		if (shdr[i].sh_offset == 0)
499c98a2727SRoger Pau Monné 			continue;
500c98a2727SRoger Pau Monné 		ksymtab = (uintptr_t)((uint8_t *)ehdr + shdr[i].sh_offset);
501c98a2727SRoger Pau Monné 		ksymtab_size = shdr[i].sh_size;
502c98a2727SRoger Pau Monné 		j = shdr[i].sh_link;
503c98a2727SRoger Pau Monné 		if (shdr[j].sh_offset == 0)
504c98a2727SRoger Pau Monné 			continue; /* Can this happen? */
505c98a2727SRoger Pau Monné 		kstrtab = (uintptr_t)((uint8_t *)ehdr + shdr[j].sh_offset);
506c98a2727SRoger Pau Monné 		break;
507c98a2727SRoger Pau Monné 	}
508c98a2727SRoger Pau Monné 
509b0663c33SRoger Pau Monné 	if (ksymtab == 0 || kstrtab == 0)
510c98a2727SRoger Pau Monné 		xc_printf(
511c98a2727SRoger Pau Monné     "Unable to load ELF symtab: could not find symtab or strtab\n");
512c98a2727SRoger Pau Monné }
513c98a2727SRoger Pau Monné #endif
514c98a2727SRoger Pau Monné 
51597baeefdSRoger Pau Monné static caddr_t
516b0663c33SRoger Pau Monné xen_legacy_pvh_parse_preload_data(uint64_t modulep)
51797baeefdSRoger Pau Monné {
518ca49b334SRoger Pau Monné 	caddr_t		 kmdp;
519ca49b334SRoger Pau Monné 	vm_ooffset_t	 off;
520ca49b334SRoger Pau Monné 	vm_paddr_t	 metadata;
52169dcb7e7SIan Lepore 	char             *envp;
522ca49b334SRoger Pau Monné 
523cfa0b7b8SRoger Pau Monné 	if (legacy_start_info->mod_start != 0) {
524cfa0b7b8SRoger Pau Monné 		preload_metadata = (caddr_t)legacy_start_info->mod_start;
525ca49b334SRoger Pau Monné 
526ca49b334SRoger Pau Monné 		kmdp = preload_search_by_type("elf kernel");
527ca49b334SRoger Pau Monné 		if (kmdp == NULL)
528ca49b334SRoger Pau Monné 			kmdp = preload_search_by_type("elf64 kernel");
529ca49b334SRoger Pau Monné 		KASSERT(kmdp != NULL, ("unable to find kernel"));
530ca49b334SRoger Pau Monné 
531ca49b334SRoger Pau Monné 		/*
532ca49b334SRoger Pau Monné 		 * Xen has relocated the metadata and the modules,
533ca49b334SRoger Pau Monné 		 * so we need to recalculate it's position. This is
534ca49b334SRoger Pau Monné 		 * done by saving the original modulep address and
535ca49b334SRoger Pau Monné 		 * then calculating the offset with mod_start,
536ca49b334SRoger Pau Monné 		 * which contains the relocated modulep address.
537ca49b334SRoger Pau Monné 		 */
538b829c841SRoger Pau Monné 		metadata = MD_FETCH(kmdp, MODINFOMD_MODULEP, vm_paddr_t);
539cfa0b7b8SRoger Pau Monné 		off = legacy_start_info->mod_start - metadata;
540ca49b334SRoger Pau Monné 
541ca49b334SRoger Pau Monné 		preload_bootstrap_relocate(off);
542ca49b334SRoger Pau Monné 
543ca49b334SRoger Pau Monné 		boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
54469dcb7e7SIan Lepore 		envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
54569dcb7e7SIan Lepore 		if (envp != NULL)
54669dcb7e7SIan Lepore 			envp += off;
547b0663c33SRoger Pau Monné 		xen_pvh_set_env(envp, NULL);
548ca49b334SRoger Pau Monné 	} else {
54997baeefdSRoger Pau Monné 		/* Parse the extra boot information given by Xen */
550b0663c33SRoger Pau Monné 		boot_parse_cmdline_delim(legacy_start_info->cmd_line, ",");
551ca49b334SRoger Pau Monné 		kmdp = NULL;
552ca49b334SRoger Pau Monné 	}
55397baeefdSRoger Pau Monné 
554b0663c33SRoger Pau Monné 	boothowto |= boot_env_to_howto();
555b0663c33SRoger Pau Monné 
556c98a2727SRoger Pau Monné #ifdef DDB
557b0663c33SRoger Pau Monné 	xen_pvh_parse_symtab();
558b0663c33SRoger Pau Monné #endif
559b0663c33SRoger Pau Monné 	return (kmdp);
560b0663c33SRoger Pau Monné }
561b0663c33SRoger Pau Monné 
562b0663c33SRoger Pau Monné static caddr_t
563b0663c33SRoger Pau Monné xen_pvh_parse_preload_data(uint64_t modulep)
564b0663c33SRoger Pau Monné {
565b0663c33SRoger Pau Monné 	caddr_t kmdp;
566b0663c33SRoger Pau Monné 	vm_ooffset_t off;
567b0663c33SRoger Pau Monné 	vm_paddr_t metadata;
568b0663c33SRoger Pau Monné 	char *envp;
569b0663c33SRoger Pau Monné 	char acpi_rsdp[19];
570b0663c33SRoger Pau Monné 
571b0663c33SRoger Pau Monné 	if (start_info->modlist_paddr != 0) {
572b0663c33SRoger Pau Monné 		struct hvm_modlist_entry *mod;
573b6d85a5fSRoger Pau Monné 		const char *cmdline;
574b0663c33SRoger Pau Monné 
575b0663c33SRoger Pau Monné 		mod = (struct hvm_modlist_entry *)
576b0663c33SRoger Pau Monné 		    (start_info->modlist_paddr + KERNBASE);
577b6d85a5fSRoger Pau Monné 		cmdline = mod[0].cmdline_paddr ?
578b6d85a5fSRoger Pau Monné 		    (const char *)(mod[0].cmdline_paddr + KERNBASE) : NULL;
579b6d85a5fSRoger Pau Monné 
580b6d85a5fSRoger Pau Monné 		if (strcmp(cmdline, "header") == 0) {
581b6d85a5fSRoger Pau Monné 			struct xen_header *header;
582b6d85a5fSRoger Pau Monné 
583b6d85a5fSRoger Pau Monné 			header = (struct xen_header *)(mod[0].paddr + KERNBASE);
584b6d85a5fSRoger Pau Monné 
585b6d85a5fSRoger Pau Monné 			if ((header->flags & XENHEADER_HAS_MODULEP_OFFSET) !=
586b6d85a5fSRoger Pau Monné 			    XENHEADER_HAS_MODULEP_OFFSET) {
587b6d85a5fSRoger Pau Monné 				xc_printf("Unable to load module metadata\n");
588b6d85a5fSRoger Pau Monné 				HYPERVISOR_shutdown(SHUTDOWN_crash);
589b6d85a5fSRoger Pau Monné 			}
590b6d85a5fSRoger Pau Monné 
591b6d85a5fSRoger Pau Monné 			preload_metadata = (caddr_t)(mod[0].paddr +
592b6d85a5fSRoger Pau Monné 			    header->modulep_offset + KERNBASE);
593b6d85a5fSRoger Pau Monné 
594b6d85a5fSRoger Pau Monné 			kmdp = preload_search_by_type("elf kernel");
595b6d85a5fSRoger Pau Monné 			if (kmdp == NULL)
596b6d85a5fSRoger Pau Monné 				kmdp = preload_search_by_type("elf64 kernel");
597b6d85a5fSRoger Pau Monné 			if (kmdp == NULL) {
598b6d85a5fSRoger Pau Monné 				xc_printf("Unable to find kernel\n");
599b6d85a5fSRoger Pau Monné 				HYPERVISOR_shutdown(SHUTDOWN_crash);
600b6d85a5fSRoger Pau Monné 			}
601b6d85a5fSRoger Pau Monné 
602b6d85a5fSRoger Pau Monné 			/*
603b6d85a5fSRoger Pau Monné 			 * Xen has relocated the metadata and the modules, so
604b6d85a5fSRoger Pau Monné 			 * we need to recalculate it's position. This is done
605b6d85a5fSRoger Pau Monné 			 * by saving the original modulep address and then
606b6d85a5fSRoger Pau Monné 			 * calculating the offset from the real modulep
607b6d85a5fSRoger Pau Monné 			 * position.
608b6d85a5fSRoger Pau Monné 			 */
609b6d85a5fSRoger Pau Monné 			metadata = MD_FETCH(kmdp, MODINFOMD_MODULEP,
610b6d85a5fSRoger Pau Monné 			    vm_paddr_t);
611b6d85a5fSRoger Pau Monné 			off = mod[0].paddr + header->modulep_offset - metadata +
612b6d85a5fSRoger Pau Monné 			    KERNBASE;
613b6d85a5fSRoger Pau Monné 		} else {
614b0663c33SRoger Pau Monné 			preload_metadata = (caddr_t)(mod[0].paddr + KERNBASE);
615b0663c33SRoger Pau Monné 
616b0663c33SRoger Pau Monné 			kmdp = preload_search_by_type("elf kernel");
617b0663c33SRoger Pau Monné 			if (kmdp == NULL)
618b0663c33SRoger Pau Monné 				kmdp = preload_search_by_type("elf64 kernel");
619b6d85a5fSRoger Pau Monné 			if (kmdp == NULL) {
620b6d85a5fSRoger Pau Monné 				xc_printf("Unable to find kernel\n");
621b6d85a5fSRoger Pau Monné 				HYPERVISOR_shutdown(SHUTDOWN_crash);
622b6d85a5fSRoger Pau Monné 			}
623b0663c33SRoger Pau Monné 
624b0663c33SRoger Pau Monné 			metadata = MD_FETCH(kmdp, MODINFOMD_MODULEP, vm_paddr_t);
625b0663c33SRoger Pau Monné 			off = mod[0].paddr + KERNBASE - metadata;
626b6d85a5fSRoger Pau Monné 		}
627b0663c33SRoger Pau Monné 
628b0663c33SRoger Pau Monné 		preload_bootstrap_relocate(off);
629b0663c33SRoger Pau Monné 
630b0663c33SRoger Pau Monné 		boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
631b0663c33SRoger Pau Monné 		envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
632b0663c33SRoger Pau Monné 		if (envp != NULL)
633b0663c33SRoger Pau Monné 			envp += off;
634b0663c33SRoger Pau Monné 		xen_pvh_set_env(envp, reject_option);
635*a2495c36SRoger Pau Monné 
636*a2495c36SRoger Pau Monné 		if (MD_FETCH(kmdp, MODINFOMD_EFI_MAP, void *) != NULL)
637*a2495c36SRoger Pau Monné 		    strlcpy(bootmethod, "UEFI", sizeof(bootmethod));
638*a2495c36SRoger Pau Monné 		else
639*a2495c36SRoger Pau Monné 		    strlcpy(bootmethod, "BIOS", sizeof(bootmethod));
640b0663c33SRoger Pau Monné 	} else {
641b0663c33SRoger Pau Monné 		/* Parse the extra boot information given by Xen */
642b0663c33SRoger Pau Monné 		if (start_info->cmdline_paddr != 0)
643b0663c33SRoger Pau Monné 			boot_parse_cmdline_delim(
644b0663c33SRoger Pau Monné 			    (char *)(start_info->cmdline_paddr + KERNBASE),
645b0663c33SRoger Pau Monné 			    ",");
646b0663c33SRoger Pau Monné 		kmdp = NULL;
647*a2495c36SRoger Pau Monné 		strlcpy(bootmethod, "XEN", sizeof(bootmethod));
648b0663c33SRoger Pau Monné 	}
649b0663c33SRoger Pau Monné 
650b0663c33SRoger Pau Monné 	boothowto |= boot_env_to_howto();
651b0663c33SRoger Pau Monné 
652b0663c33SRoger Pau Monné 	snprintf(acpi_rsdp, sizeof(acpi_rsdp), "%#" PRIx64,
653b0663c33SRoger Pau Monné 	    start_info->rsdp_paddr);
654b0663c33SRoger Pau Monné 	kern_setenv("acpi.rsdp", acpi_rsdp);
655b0663c33SRoger Pau Monné 
656b0663c33SRoger Pau Monné #ifdef DDB
657b0663c33SRoger Pau Monné 	xen_pvh_parse_symtab();
658c98a2727SRoger Pau Monné #endif
659ca49b334SRoger Pau Monné 	return (kmdp);
66097baeefdSRoger Pau Monné }
6611e69553eSRoger Pau Monné 
6621e69553eSRoger Pau Monné static void
663b0663c33SRoger Pau Monné xen_pvh_parse_memmap(caddr_t kmdp, vm_paddr_t *physmap, int *physmap_idx)
6641e69553eSRoger Pau Monné {
6651e69553eSRoger Pau Monné 	struct xen_memory_map memmap;
6661e69553eSRoger Pau Monné 	u_int32_t size;
6671e69553eSRoger Pau Monné 	int rc;
6681e69553eSRoger Pau Monné 
6691e69553eSRoger Pau Monné 	/* Fetch the E820 map from Xen */
6701e69553eSRoger Pau Monné 	memmap.nr_entries = MAX_E820_ENTRIES;
6711e69553eSRoger Pau Monné 	set_xen_guest_handle(memmap.buffer, xen_smap);
6721e69553eSRoger Pau Monné 	rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap);
673b0663c33SRoger Pau Monné 	if (rc) {
674b0663c33SRoger Pau Monné 		xc_printf("ERROR: unable to fetch Xen E820 memory map: %d\n",
675b0663c33SRoger Pau Monné 		    rc);
676b0663c33SRoger Pau Monné 		HYPERVISOR_shutdown(SHUTDOWN_crash);
677b0663c33SRoger Pau Monné 	}
678b0663c33SRoger Pau Monné 
6791e69553eSRoger Pau Monné 	size = memmap.nr_entries * sizeof(xen_smap[0]);
6801e69553eSRoger Pau Monné 
6811e69553eSRoger Pau Monné 	bios_add_smap_entries(xen_smap, size, physmap, physmap_idx);
6821e69553eSRoger Pau Monné }
683