xref: /freebsd/sys/x86/xen/pv.c (revision 1e69553ed1dea6b8cb6c97a49a72e811f9bd7cde)
11a9cdd37SRoger Pau Monné /*
21a9cdd37SRoger Pau Monné  * Copyright (c) 2004 Christian Limpach.
31a9cdd37SRoger Pau Monné  * Copyright (c) 2004-2006,2008 Kip Macy
41a9cdd37SRoger Pau Monné  * Copyright (c) 2013 Roger Pau Monné <roger.pau@citrix.com>
51a9cdd37SRoger Pau Monné  * All rights reserved.
61a9cdd37SRoger Pau Monné  *
71a9cdd37SRoger Pau Monné  * Redistribution and use in source and binary forms, with or without
81a9cdd37SRoger Pau Monné  * modification, are permitted provided that the following conditions
91a9cdd37SRoger Pau Monné  * are met:
101a9cdd37SRoger Pau Monné  * 1. Redistributions of source code must retain the above copyright
111a9cdd37SRoger Pau Monné  *    notice, this list of conditions and the following disclaimer.
121a9cdd37SRoger Pau Monné  * 2. Redistributions in binary form must reproduce the above copyright
131a9cdd37SRoger Pau Monné  *    notice, this list of conditions and the following disclaimer in the
141a9cdd37SRoger Pau Monné  *    documentation and/or other materials provided with the distribution.
151a9cdd37SRoger Pau Monné  *
161a9cdd37SRoger Pau Monné  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND
171a9cdd37SRoger Pau Monné  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
181a9cdd37SRoger Pau Monné  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
191a9cdd37SRoger Pau Monné  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
201a9cdd37SRoger Pau Monné  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
211a9cdd37SRoger Pau Monné  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
221a9cdd37SRoger Pau Monné  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
231a9cdd37SRoger Pau Monné  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
241a9cdd37SRoger Pau Monné  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251a9cdd37SRoger Pau Monné  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261a9cdd37SRoger Pau Monné  * SUCH DAMAGE.
271a9cdd37SRoger Pau Monné  */
281a9cdd37SRoger Pau Monné 
291a9cdd37SRoger Pau Monné #include <sys/cdefs.h>
301a9cdd37SRoger Pau Monné __FBSDID("$FreeBSD$");
311a9cdd37SRoger Pau Monné 
321a9cdd37SRoger Pau Monné #include <sys/param.h>
331a9cdd37SRoger Pau Monné #include <sys/bus.h>
341a9cdd37SRoger Pau Monné #include <sys/kernel.h>
351a9cdd37SRoger Pau Monné #include <sys/reboot.h>
361a9cdd37SRoger Pau Monné #include <sys/systm.h>
371a9cdd37SRoger Pau Monné #include <sys/lock.h>
381a9cdd37SRoger Pau Monné #include <sys/rwlock.h>
39aa389b4fSRoger Pau Monné #include <sys/boot.h>
4097baeefdSRoger Pau Monné #include <sys/ctype.h>
411a9cdd37SRoger Pau Monné 
421a9cdd37SRoger Pau Monné #include <vm/vm.h>
431a9cdd37SRoger Pau Monné #include <vm/vm_extern.h>
441a9cdd37SRoger Pau Monné #include <vm/vm_kern.h>
451a9cdd37SRoger Pau Monné #include <vm/vm_page.h>
461a9cdd37SRoger Pau Monné #include <vm/vm_map.h>
471a9cdd37SRoger Pau Monné #include <vm/vm_object.h>
481a9cdd37SRoger Pau Monné #include <vm/vm_pager.h>
491a9cdd37SRoger Pau Monné #include <vm/vm_param.h>
501a9cdd37SRoger Pau Monné 
5197baeefdSRoger Pau Monné #include <x86/init.h>
52*1e69553eSRoger Pau Monné #include <machine/pc/bios.h>
5397baeefdSRoger Pau Monné 
541a9cdd37SRoger Pau Monné #include <xen/xen-os.h>
551a9cdd37SRoger Pau Monné #include <xen/hypervisor.h>
561a9cdd37SRoger Pau Monné 
575f05c794SRoger Pau Monné #include <dev/xen/timer/timer.h>
585f05c794SRoger Pau Monné 
591a9cdd37SRoger Pau Monné /* Native initial function */
601a9cdd37SRoger Pau Monné extern u_int64_t hammer_time(u_int64_t, u_int64_t);
611a9cdd37SRoger Pau Monné /* Xen initial function */
621a9cdd37SRoger Pau Monné uint64_t hammer_time_xen(start_info_t *, uint64_t);
631a9cdd37SRoger Pau Monné 
64*1e69553eSRoger Pau Monné #define MAX_E820_ENTRIES	128
65*1e69553eSRoger Pau Monné 
6697baeefdSRoger Pau Monné /*--------------------------- Forward Declarations ---------------------------*/
6797baeefdSRoger Pau Monné static caddr_t xen_pv_parse_preload_data(u_int64_t);
68*1e69553eSRoger Pau Monné static void xen_pv_parse_memmap(caddr_t, vm_paddr_t *, int *);
6997baeefdSRoger Pau Monné 
7097baeefdSRoger Pau Monné /*-------------------------------- Global Data -------------------------------*/
7197baeefdSRoger Pau Monné /* Xen init_ops implementation. */
7297baeefdSRoger Pau Monné struct init_ops xen_init_ops = {
7397baeefdSRoger Pau Monné 	.parse_preload_data =	xen_pv_parse_preload_data,
745f05c794SRoger Pau Monné 	.early_clock_source_init =	xen_clock_init,
755f05c794SRoger Pau Monné 	.early_delay =			xen_delay,
76*1e69553eSRoger Pau Monné 	.parse_memmap =			xen_pv_parse_memmap,
7797baeefdSRoger Pau Monné };
7897baeefdSRoger Pau Monné 
79*1e69553eSRoger Pau Monné static struct bios_smap xen_smap[MAX_E820_ENTRIES];
80*1e69553eSRoger Pau Monné 
8197baeefdSRoger Pau Monné /*-------------------------------- Xen PV init -------------------------------*/
821a9cdd37SRoger Pau Monné /*
831a9cdd37SRoger Pau Monné  * First function called by the Xen PVH boot sequence.
841a9cdd37SRoger Pau Monné  *
851a9cdd37SRoger Pau Monné  * Set some Xen global variables and prepare the environment so it is
861a9cdd37SRoger Pau Monné  * as similar as possible to what native FreeBSD init function expects.
871a9cdd37SRoger Pau Monné  */
881a9cdd37SRoger Pau Monné uint64_t
891a9cdd37SRoger Pau Monné hammer_time_xen(start_info_t *si, uint64_t xenstack)
901a9cdd37SRoger Pau Monné {
911a9cdd37SRoger Pau Monné 	uint64_t physfree;
921a9cdd37SRoger Pau Monné 	uint64_t *PT4 = (u_int64_t *)xenstack;
931a9cdd37SRoger Pau Monné 	uint64_t *PT3 = (u_int64_t *)(xenstack + PAGE_SIZE);
941a9cdd37SRoger Pau Monné 	uint64_t *PT2 = (u_int64_t *)(xenstack + 2 * PAGE_SIZE);
951a9cdd37SRoger Pau Monné 	int i;
961a9cdd37SRoger Pau Monné 
971a9cdd37SRoger Pau Monné 	xen_domain_type = XEN_PV_DOMAIN;
981a9cdd37SRoger Pau Monné 	vm_guest = VM_GUEST_XEN;
991a9cdd37SRoger Pau Monné 
1001a9cdd37SRoger Pau Monné 	if ((si == NULL) || (xenstack == 0)) {
101c203fa69SRoger Pau Monné 		xc_printf("ERROR: invalid start_info or xen stack, halting\n");
1021a9cdd37SRoger Pau Monné 		HYPERVISOR_shutdown(SHUTDOWN_crash);
1031a9cdd37SRoger Pau Monné 	}
1041a9cdd37SRoger Pau Monné 
105c203fa69SRoger Pau Monné 	xc_printf("FreeBSD PVH running on %s\n", si->magic);
106c203fa69SRoger Pau Monné 
1071a9cdd37SRoger Pau Monné 	/* We use 3 pages of xen stack for the boot pagetables */
1081a9cdd37SRoger Pau Monné 	physfree = xenstack + 3 * PAGE_SIZE - KERNBASE;
1091a9cdd37SRoger Pau Monné 
1101a9cdd37SRoger Pau Monné 	/* Setup Xen global variables */
1111a9cdd37SRoger Pau Monné 	HYPERVISOR_start_info = si;
1121a9cdd37SRoger Pau Monné 	HYPERVISOR_shared_info =
1131a9cdd37SRoger Pau Monné 	    (shared_info_t *)(si->shared_info + KERNBASE);
1141a9cdd37SRoger Pau Monné 
1151a9cdd37SRoger Pau Monné 	/*
1161a9cdd37SRoger Pau Monné 	 * Setup some misc global variables for Xen devices
1171a9cdd37SRoger Pau Monné 	 *
1181a9cdd37SRoger Pau Monné 	 * XXX: Devices that need these specific variables should
1191a9cdd37SRoger Pau Monné 	 *      be rewritten to fetch this info by themselves from the
1201a9cdd37SRoger Pau Monné 	 *      start_info page.
1211a9cdd37SRoger Pau Monné 	 */
1221a9cdd37SRoger Pau Monné 	xen_store = (struct xenstore_domain_interface *)
1231a9cdd37SRoger Pau Monné 	    (ptoa(si->store_mfn) + KERNBASE);
124c203fa69SRoger Pau Monné 	console_page = (char *)(ptoa(si->console.domU.mfn) + KERNBASE);
1251a9cdd37SRoger Pau Monné 
1261a9cdd37SRoger Pau Monné 	/*
1271a9cdd37SRoger Pau Monné 	 * Use the stack Xen gives us to build the page tables
1281a9cdd37SRoger Pau Monné 	 * as native FreeBSD expects to find them (created
1291a9cdd37SRoger Pau Monné 	 * by the boot trampoline).
1301a9cdd37SRoger Pau Monné 	 */
1311a9cdd37SRoger Pau Monné 	for (i = 0; i < (PAGE_SIZE / sizeof(uint64_t)); i++) {
1321a9cdd37SRoger Pau Monné 		/* Each slot of the level 4 pages points to the same level 3 page */
1331a9cdd37SRoger Pau Monné 		PT4[i] = ((uint64_t)&PT3[0]) - KERNBASE;
1341a9cdd37SRoger Pau Monné 		PT4[i] |= PG_V | PG_RW | PG_U;
1351a9cdd37SRoger Pau Monné 
1361a9cdd37SRoger Pau Monné 		/* Each slot of the level 3 pages points to the same level 2 page */
1371a9cdd37SRoger Pau Monné 		PT3[i] = ((uint64_t)&PT2[0]) - KERNBASE;
1381a9cdd37SRoger Pau Monné 		PT3[i] |= PG_V | PG_RW | PG_U;
1391a9cdd37SRoger Pau Monné 
1401a9cdd37SRoger Pau Monné 		/* The level 2 page slots are mapped with 2MB pages for 1GB. */
1411a9cdd37SRoger Pau Monné 		PT2[i] = i * (2 * 1024 * 1024);
1421a9cdd37SRoger Pau Monné 		PT2[i] |= PG_V | PG_RW | PG_PS | PG_U;
1431a9cdd37SRoger Pau Monné 	}
1441a9cdd37SRoger Pau Monné 	load_cr3(((uint64_t)&PT4[0]) - KERNBASE);
1451a9cdd37SRoger Pau Monné 
14697baeefdSRoger Pau Monné 	/* Set the hooks for early functions that diverge from bare metal */
14797baeefdSRoger Pau Monné 	init_ops = xen_init_ops;
14897baeefdSRoger Pau Monné 
1491a9cdd37SRoger Pau Monné 	/* Now we can jump into the native init function */
1501a9cdd37SRoger Pau Monné 	return (hammer_time(0, physfree));
1511a9cdd37SRoger Pau Monné }
15297baeefdSRoger Pau Monné 
15397baeefdSRoger Pau Monné /*-------------------------------- PV specific -------------------------------*/
15497baeefdSRoger Pau Monné /*
15597baeefdSRoger Pau Monné  * Functions to convert the "extra" parameters passed by Xen
15697baeefdSRoger Pau Monné  * into FreeBSD boot options.
15797baeefdSRoger Pau Monné  */
15897baeefdSRoger Pau Monné static void
15997baeefdSRoger Pau Monné xen_pv_set_env(void)
16097baeefdSRoger Pau Monné {
16197baeefdSRoger Pau Monné 	char *cmd_line_next, *cmd_line;
16297baeefdSRoger Pau Monné 	size_t env_size;
16397baeefdSRoger Pau Monné 
16497baeefdSRoger Pau Monné 	cmd_line = HYPERVISOR_start_info->cmd_line;
16597baeefdSRoger Pau Monné 	env_size = sizeof(HYPERVISOR_start_info->cmd_line);
16697baeefdSRoger Pau Monné 
16797baeefdSRoger Pau Monné 	/* Skip leading spaces */
16897baeefdSRoger Pau Monné 	for (; isspace(*cmd_line) && (env_size != 0); cmd_line++)
16997baeefdSRoger Pau Monné 		env_size--;
17097baeefdSRoger Pau Monné 
17197baeefdSRoger Pau Monné 	/* Replace ',' with '\0' */
17297baeefdSRoger Pau Monné 	for (cmd_line_next = cmd_line; strsep(&cmd_line_next, ",") != NULL;)
17397baeefdSRoger Pau Monné 		;
17497baeefdSRoger Pau Monné 
17597baeefdSRoger Pau Monné 	init_static_kenv(cmd_line, env_size);
17697baeefdSRoger Pau Monné }
17797baeefdSRoger Pau Monné 
17897baeefdSRoger Pau Monné static void
17997baeefdSRoger Pau Monné xen_pv_set_boothowto(void)
18097baeefdSRoger Pau Monné {
18197baeefdSRoger Pau Monné 	int i;
18297baeefdSRoger Pau Monné 
18397baeefdSRoger Pau Monné 	/* get equivalents from the environment */
18497baeefdSRoger Pau Monné 	for (i = 0; howto_names[i].ev != NULL; i++) {
18597baeefdSRoger Pau Monné 		if (getenv(howto_names[i].ev) != NULL)
18697baeefdSRoger Pau Monné 			boothowto |= howto_names[i].mask;
18797baeefdSRoger Pau Monné 	}
18897baeefdSRoger Pau Monné }
18997baeefdSRoger Pau Monné 
19097baeefdSRoger Pau Monné static caddr_t
19197baeefdSRoger Pau Monné xen_pv_parse_preload_data(u_int64_t modulep)
19297baeefdSRoger Pau Monné {
19397baeefdSRoger Pau Monné 	/* Parse the extra boot information given by Xen */
19497baeefdSRoger Pau Monné 	xen_pv_set_env();
19597baeefdSRoger Pau Monné 	xen_pv_set_boothowto();
19697baeefdSRoger Pau Monné 
19797baeefdSRoger Pau Monné 	return (NULL);
19897baeefdSRoger Pau Monné }
199*1e69553eSRoger Pau Monné 
200*1e69553eSRoger Pau Monné static void
201*1e69553eSRoger Pau Monné xen_pv_parse_memmap(caddr_t kmdp, vm_paddr_t *physmap, int *physmap_idx)
202*1e69553eSRoger Pau Monné {
203*1e69553eSRoger Pau Monné 	struct xen_memory_map memmap;
204*1e69553eSRoger Pau Monné 	u_int32_t size;
205*1e69553eSRoger Pau Monné 	int rc;
206*1e69553eSRoger Pau Monné 
207*1e69553eSRoger Pau Monné 	/* Fetch the E820 map from Xen */
208*1e69553eSRoger Pau Monné 	memmap.nr_entries = MAX_E820_ENTRIES;
209*1e69553eSRoger Pau Monné 	set_xen_guest_handle(memmap.buffer, xen_smap);
210*1e69553eSRoger Pau Monné 	rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap);
211*1e69553eSRoger Pau Monné 	if (rc)
212*1e69553eSRoger Pau Monné 		panic("unable to fetch Xen E820 memory map");
213*1e69553eSRoger Pau Monné 	size = memmap.nr_entries * sizeof(xen_smap[0]);
214*1e69553eSRoger Pau Monné 
215*1e69553eSRoger Pau Monné 	bios_add_smap_entries(xen_smap, size, physmap, physmap_idx);
216*1e69553eSRoger Pau Monné }
217