xref: /freebsd/sys/x86/xen/pv.c (revision 5f05c79450788b33bd82738ee27bf6d0ceeb12ca)
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>
5297baeefdSRoger Pau Monné 
531a9cdd37SRoger Pau Monné #include <xen/xen-os.h>
541a9cdd37SRoger Pau Monné #include <xen/hypervisor.h>
551a9cdd37SRoger Pau Monné 
56*5f05c794SRoger Pau Monné #include <dev/xen/timer/timer.h>
57*5f05c794SRoger Pau Monné 
581a9cdd37SRoger Pau Monné /* Native initial function */
591a9cdd37SRoger Pau Monné extern u_int64_t hammer_time(u_int64_t, u_int64_t);
601a9cdd37SRoger Pau Monné /* Xen initial function */
611a9cdd37SRoger Pau Monné uint64_t hammer_time_xen(start_info_t *, uint64_t);
621a9cdd37SRoger Pau Monné 
6397baeefdSRoger Pau Monné /*--------------------------- Forward Declarations ---------------------------*/
6497baeefdSRoger Pau Monné static caddr_t xen_pv_parse_preload_data(u_int64_t);
6597baeefdSRoger Pau Monné 
6697baeefdSRoger Pau Monné /*-------------------------------- Global Data -------------------------------*/
6797baeefdSRoger Pau Monné /* Xen init_ops implementation. */
6897baeefdSRoger Pau Monné struct init_ops xen_init_ops = {
6997baeefdSRoger Pau Monné 	.parse_preload_data =	xen_pv_parse_preload_data,
70*5f05c794SRoger Pau Monné 	.early_clock_source_init =	xen_clock_init,
71*5f05c794SRoger Pau Monné 	.early_delay =			xen_delay,
7297baeefdSRoger Pau Monné };
7397baeefdSRoger Pau Monné 
7497baeefdSRoger Pau Monné /*-------------------------------- Xen PV init -------------------------------*/
751a9cdd37SRoger Pau Monné /*
761a9cdd37SRoger Pau Monné  * First function called by the Xen PVH boot sequence.
771a9cdd37SRoger Pau Monné  *
781a9cdd37SRoger Pau Monné  * Set some Xen global variables and prepare the environment so it is
791a9cdd37SRoger Pau Monné  * as similar as possible to what native FreeBSD init function expects.
801a9cdd37SRoger Pau Monné  */
811a9cdd37SRoger Pau Monné uint64_t
821a9cdd37SRoger Pau Monné hammer_time_xen(start_info_t *si, uint64_t xenstack)
831a9cdd37SRoger Pau Monné {
841a9cdd37SRoger Pau Monné 	uint64_t physfree;
851a9cdd37SRoger Pau Monné 	uint64_t *PT4 = (u_int64_t *)xenstack;
861a9cdd37SRoger Pau Monné 	uint64_t *PT3 = (u_int64_t *)(xenstack + PAGE_SIZE);
871a9cdd37SRoger Pau Monné 	uint64_t *PT2 = (u_int64_t *)(xenstack + 2 * PAGE_SIZE);
881a9cdd37SRoger Pau Monné 	int i;
891a9cdd37SRoger Pau Monné 
901a9cdd37SRoger Pau Monné 	xen_domain_type = XEN_PV_DOMAIN;
911a9cdd37SRoger Pau Monné 	vm_guest = VM_GUEST_XEN;
921a9cdd37SRoger Pau Monné 
931a9cdd37SRoger Pau Monné 	if ((si == NULL) || (xenstack == 0)) {
94c203fa69SRoger Pau Monné 		xc_printf("ERROR: invalid start_info or xen stack, halting\n");
951a9cdd37SRoger Pau Monné 		HYPERVISOR_shutdown(SHUTDOWN_crash);
961a9cdd37SRoger Pau Monné 	}
971a9cdd37SRoger Pau Monné 
98c203fa69SRoger Pau Monné 	xc_printf("FreeBSD PVH running on %s\n", si->magic);
99c203fa69SRoger Pau Monné 
1001a9cdd37SRoger Pau Monné 	/* We use 3 pages of xen stack for the boot pagetables */
1011a9cdd37SRoger Pau Monné 	physfree = xenstack + 3 * PAGE_SIZE - KERNBASE;
1021a9cdd37SRoger Pau Monné 
1031a9cdd37SRoger Pau Monné 	/* Setup Xen global variables */
1041a9cdd37SRoger Pau Monné 	HYPERVISOR_start_info = si;
1051a9cdd37SRoger Pau Monné 	HYPERVISOR_shared_info =
1061a9cdd37SRoger Pau Monné 	    (shared_info_t *)(si->shared_info + KERNBASE);
1071a9cdd37SRoger Pau Monné 
1081a9cdd37SRoger Pau Monné 	/*
1091a9cdd37SRoger Pau Monné 	 * Setup some misc global variables for Xen devices
1101a9cdd37SRoger Pau Monné 	 *
1111a9cdd37SRoger Pau Monné 	 * XXX: Devices that need these specific variables should
1121a9cdd37SRoger Pau Monné 	 *      be rewritten to fetch this info by themselves from the
1131a9cdd37SRoger Pau Monné 	 *      start_info page.
1141a9cdd37SRoger Pau Monné 	 */
1151a9cdd37SRoger Pau Monné 	xen_store = (struct xenstore_domain_interface *)
1161a9cdd37SRoger Pau Monné 	    (ptoa(si->store_mfn) + KERNBASE);
117c203fa69SRoger Pau Monné 	console_page = (char *)(ptoa(si->console.domU.mfn) + KERNBASE);
1181a9cdd37SRoger Pau Monné 
1191a9cdd37SRoger Pau Monné 	/*
1201a9cdd37SRoger Pau Monné 	 * Use the stack Xen gives us to build the page tables
1211a9cdd37SRoger Pau Monné 	 * as native FreeBSD expects to find them (created
1221a9cdd37SRoger Pau Monné 	 * by the boot trampoline).
1231a9cdd37SRoger Pau Monné 	 */
1241a9cdd37SRoger Pau Monné 	for (i = 0; i < (PAGE_SIZE / sizeof(uint64_t)); i++) {
1251a9cdd37SRoger Pau Monné 		/* Each slot of the level 4 pages points to the same level 3 page */
1261a9cdd37SRoger Pau Monné 		PT4[i] = ((uint64_t)&PT3[0]) - KERNBASE;
1271a9cdd37SRoger Pau Monné 		PT4[i] |= PG_V | PG_RW | PG_U;
1281a9cdd37SRoger Pau Monné 
1291a9cdd37SRoger Pau Monné 		/* Each slot of the level 3 pages points to the same level 2 page */
1301a9cdd37SRoger Pau Monné 		PT3[i] = ((uint64_t)&PT2[0]) - KERNBASE;
1311a9cdd37SRoger Pau Monné 		PT3[i] |= PG_V | PG_RW | PG_U;
1321a9cdd37SRoger Pau Monné 
1331a9cdd37SRoger Pau Monné 		/* The level 2 page slots are mapped with 2MB pages for 1GB. */
1341a9cdd37SRoger Pau Monné 		PT2[i] = i * (2 * 1024 * 1024);
1351a9cdd37SRoger Pau Monné 		PT2[i] |= PG_V | PG_RW | PG_PS | PG_U;
1361a9cdd37SRoger Pau Monné 	}
1371a9cdd37SRoger Pau Monné 	load_cr3(((uint64_t)&PT4[0]) - KERNBASE);
1381a9cdd37SRoger Pau Monné 
13997baeefdSRoger Pau Monné 	/* Set the hooks for early functions that diverge from bare metal */
14097baeefdSRoger Pau Monné 	init_ops = xen_init_ops;
14197baeefdSRoger Pau Monné 
1421a9cdd37SRoger Pau Monné 	/* Now we can jump into the native init function */
1431a9cdd37SRoger Pau Monné 	return (hammer_time(0, physfree));
1441a9cdd37SRoger Pau Monné }
14597baeefdSRoger Pau Monné 
14697baeefdSRoger Pau Monné /*-------------------------------- PV specific -------------------------------*/
14797baeefdSRoger Pau Monné /*
14897baeefdSRoger Pau Monné  * Functions to convert the "extra" parameters passed by Xen
14997baeefdSRoger Pau Monné  * into FreeBSD boot options.
15097baeefdSRoger Pau Monné  */
15197baeefdSRoger Pau Monné static void
15297baeefdSRoger Pau Monné xen_pv_set_env(void)
15397baeefdSRoger Pau Monné {
15497baeefdSRoger Pau Monné 	char *cmd_line_next, *cmd_line;
15597baeefdSRoger Pau Monné 	size_t env_size;
15697baeefdSRoger Pau Monné 
15797baeefdSRoger Pau Monné 	cmd_line = HYPERVISOR_start_info->cmd_line;
15897baeefdSRoger Pau Monné 	env_size = sizeof(HYPERVISOR_start_info->cmd_line);
15997baeefdSRoger Pau Monné 
16097baeefdSRoger Pau Monné 	/* Skip leading spaces */
16197baeefdSRoger Pau Monné 	for (; isspace(*cmd_line) && (env_size != 0); cmd_line++)
16297baeefdSRoger Pau Monné 		env_size--;
16397baeefdSRoger Pau Monné 
16497baeefdSRoger Pau Monné 	/* Replace ',' with '\0' */
16597baeefdSRoger Pau Monné 	for (cmd_line_next = cmd_line; strsep(&cmd_line_next, ",") != NULL;)
16697baeefdSRoger Pau Monné 		;
16797baeefdSRoger Pau Monné 
16897baeefdSRoger Pau Monné 	init_static_kenv(cmd_line, env_size);
16997baeefdSRoger Pau Monné }
17097baeefdSRoger Pau Monné 
17197baeefdSRoger Pau Monné static void
17297baeefdSRoger Pau Monné xen_pv_set_boothowto(void)
17397baeefdSRoger Pau Monné {
17497baeefdSRoger Pau Monné 	int i;
17597baeefdSRoger Pau Monné 
17697baeefdSRoger Pau Monné 	/* get equivalents from the environment */
17797baeefdSRoger Pau Monné 	for (i = 0; howto_names[i].ev != NULL; i++) {
17897baeefdSRoger Pau Monné 		if (getenv(howto_names[i].ev) != NULL)
17997baeefdSRoger Pau Monné 			boothowto |= howto_names[i].mask;
18097baeefdSRoger Pau Monné 	}
18197baeefdSRoger Pau Monné }
18297baeefdSRoger Pau Monné 
18397baeefdSRoger Pau Monné static caddr_t
18497baeefdSRoger Pau Monné xen_pv_parse_preload_data(u_int64_t modulep)
18597baeefdSRoger Pau Monné {
18697baeefdSRoger Pau Monné 	/* Parse the extra boot information given by Xen */
18797baeefdSRoger Pau Monné 	xen_pv_set_env();
18897baeefdSRoger Pau Monné 	xen_pv_set_boothowto();
18997baeefdSRoger Pau Monné 
19097baeefdSRoger Pau Monné 	return (NULL);
19197baeefdSRoger Pau Monné }
192