control.c revision 222975
1/*-
2 * Copyright (c) 2010 Justin T. Gibbs, Spectra Logic Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions, and the following disclaimer,
10 *    without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 *    substantially similar to the "NO WARRANTY" disclaimer below
13 *    ("Disclaimer") and any redistribution must be conditioned upon
14 *    including a substantially similar Disclaimer requirement for further
15 *    binary redistribution.
16 *
17 * NO WARRANTY
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGES.
29 */
30
31/*-
32 * PV suspend/resume support:
33 *
34 * Copyright (c) 2004 Christian Limpach.
35 * Copyright (c) 2004-2006,2008 Kip Macy
36 * All rights reserved.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 *    notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 *    notice, this list of conditions and the following disclaimer in the
45 *    documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 *    must display the following acknowledgement:
48 *      This product includes software developed by Christian Limpach.
49 * 4. The name of the author may not be used to endorse or promote products
50 *    derived from this software without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
53 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
54 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
55 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
56 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
57 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
58 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
59 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
61 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62 */
63
64/*-
65 * HVM suspend/resume support:
66 *
67 * Copyright (c) 2008 Citrix Systems, Inc.
68 * All rights reserved.
69 *
70 * Redistribution and use in source and binary forms, with or without
71 * modification, are permitted provided that the following conditions
72 * are met:
73 * 1. Redistributions of source code must retain the above copyright
74 *    notice, this list of conditions and the following disclaimer.
75 * 2. Redistributions in binary form must reproduce the above copyright
76 *    notice, this list of conditions and the following disclaimer in the
77 *    documentation and/or other materials provided with the distribution.
78 *
79 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
80 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
81 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
82 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
83 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
84 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
85 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
86 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
87 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
88 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
89 * SUCH DAMAGE.
90 */
91#include <sys/cdefs.h>
92__FBSDID("$FreeBSD: head/sys/dev/xen/control/control.c 222975 2011-06-11 04:59:01Z gibbs $");
93
94/**
95 * \file control.c
96 *
97 * \brief Device driver to repond to control domain events that impact
98 *        this VM.
99 */
100
101#include <sys/param.h>
102#include <sys/systm.h>
103#include <sys/kernel.h>
104#include <sys/malloc.h>
105
106#include <sys/bio.h>
107#include <sys/bus.h>
108#include <sys/conf.h>
109#include <sys/disk.h>
110#include <sys/fcntl.h>
111#include <sys/filedesc.h>
112#include <sys/kdb.h>
113#include <sys/module.h>
114#include <sys/namei.h>
115#include <sys/proc.h>
116#include <sys/reboot.h>
117#include <sys/rman.h>
118#include <sys/taskqueue.h>
119#include <sys/types.h>
120#include <sys/vnode.h>
121
122#ifndef XENHVM
123#include <sys/sched.h>
124#include <sys/smp.h>
125#endif
126
127
128#include <geom/geom.h>
129
130#include <machine/_inttypes.h>
131#include <machine/xen/xen-os.h>
132
133#include <vm/vm.h>
134#include <vm/vm_extern.h>
135#include <vm/vm_kern.h>
136
137#include <xen/blkif.h>
138#include <xen/evtchn.h>
139#include <xen/gnttab.h>
140#include <xen/xen_intr.h>
141
142#include <xen/interface/event_channel.h>
143#include <xen/interface/grant_table.h>
144
145#include <xen/xenbus/xenbusvar.h>
146
147#define NUM_ELEMENTS(x) (sizeof(x) / sizeof(*(x)))
148
149/*--------------------------- Forward Declarations --------------------------*/
150/** Function signature for shutdown event handlers. */
151typedef	void (xctrl_shutdown_handler_t)(void);
152
153static xctrl_shutdown_handler_t xctrl_poweroff;
154static xctrl_shutdown_handler_t xctrl_reboot;
155static xctrl_shutdown_handler_t xctrl_suspend;
156static xctrl_shutdown_handler_t xctrl_crash;
157static xctrl_shutdown_handler_t xctrl_halt;
158
159/*-------------------------- Private Data Structures -------------------------*/
160/** Element type for lookup table of event name to handler. */
161struct xctrl_shutdown_reason {
162	const char		 *name;
163	xctrl_shutdown_handler_t *handler;
164};
165
166/** Lookup table for shutdown event name to handler. */
167static struct xctrl_shutdown_reason xctrl_shutdown_reasons[] = {
168	{ "poweroff", xctrl_poweroff },
169	{ "reboot",   xctrl_reboot   },
170	{ "suspend",  xctrl_suspend  },
171	{ "crash",    xctrl_crash    },
172	{ "halt",     xctrl_halt     },
173};
174
175struct xctrl_softc {
176	struct xs_watch    xctrl_watch;
177};
178
179/*------------------------------ Event Handlers ------------------------------*/
180static void
181xctrl_poweroff()
182{
183	shutdown_nice(RB_POWEROFF|RB_HALT);
184}
185
186static void
187xctrl_reboot()
188{
189	shutdown_nice(0);
190}
191
192#ifndef XENHVM
193extern void xencons_suspend(void);
194extern void xencons_resume(void);
195
196/* Full PV mode suspension. */
197static void
198xctrl_suspend()
199{
200	int i, j, k, fpp;
201	unsigned long max_pfn, start_info_mfn;
202
203#ifdef SMP
204	struct thread *td;
205	cpuset_t map;
206	/*
207	 * Bind us to CPU 0 and stop any other VCPUs.
208	 */
209	td = curthread;
210	thread_lock(td);
211	sched_bind(td, 0);
212	thread_unlock(td);
213	KASSERT(PCPU_GET(cpuid) == 0, ("xen_suspend: not running on cpu 0"));
214
215	sched_pin();
216	map = PCPU_GET(other_cpus);
217	sched_unpin();
218	CPU_NAND(&map, &stopped_cpus);
219	if (!CPU_EMPTY(&map))
220		stop_cpus(map);
221#endif
222
223	if (DEVICE_SUSPEND(root_bus) != 0) {
224		printf("xen_suspend: device_suspend failed\n");
225#ifdef SMP
226		if (!CPU_EMPTY(&map))
227			restart_cpus(map);
228#endif
229		return;
230	}
231
232	local_irq_disable();
233
234	xencons_suspend();
235	gnttab_suspend();
236
237	max_pfn = HYPERVISOR_shared_info->arch.max_pfn;
238
239	void *shared_info = HYPERVISOR_shared_info;
240	HYPERVISOR_shared_info = NULL;
241	pmap_kremove((vm_offset_t) shared_info);
242	PT_UPDATES_FLUSH();
243
244	xen_start_info->store_mfn = MFNTOPFN(xen_start_info->store_mfn);
245	xen_start_info->console.domU.mfn = MFNTOPFN(xen_start_info->console.domU.mfn);
246
247	/*
248	 * We'll stop somewhere inside this hypercall. When it returns,
249	 * we'll start resuming after the restore.
250	 */
251	start_info_mfn = VTOMFN(xen_start_info);
252	pmap_suspend();
253	HYPERVISOR_suspend(start_info_mfn);
254	pmap_resume();
255
256	pmap_kenter_ma((vm_offset_t) shared_info, xen_start_info->shared_info);
257	HYPERVISOR_shared_info = shared_info;
258
259	HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
260		VTOMFN(xen_pfn_to_mfn_frame_list_list);
261
262	fpp = PAGE_SIZE/sizeof(unsigned long);
263	for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) {
264		if ((j % fpp) == 0) {
265			k++;
266			xen_pfn_to_mfn_frame_list_list[k] =
267				VTOMFN(xen_pfn_to_mfn_frame_list[k]);
268			j = 0;
269		}
270		xen_pfn_to_mfn_frame_list[k][j] =
271			VTOMFN(&xen_phys_machine[i]);
272	}
273	HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
274
275	gnttab_resume();
276	irq_resume();
277	local_irq_enable();
278	xencons_resume();
279
280#ifdef CONFIG_SMP
281	for_each_cpu(i)
282		vcpu_prepare(i);
283
284#endif
285	/*
286	 * Only resume xenbus /after/ we've prepared our VCPUs; otherwise
287	 * the VCPU hotplug callback can race with our vcpu_prepare
288	 */
289	DEVICE_RESUME(root_bus);
290
291#ifdef SMP
292	thread_lock(curthread);
293	sched_unbind(curthread);
294	thread_unlock(curthread);
295	if (!CPU_EMPTY(&map))
296		restart_cpus(map);
297#endif
298}
299
300static void
301xen_pv_shutdown_final(void *arg, int howto)
302{
303	/*
304	 * Inform the hypervisor that shutdown is complete.
305	 * This is not necessary in HVM domains since Xen
306	 * emulates ACPI in that mode and FreeBSD's ACPI
307	 * support will request this transition.
308	 */
309	if (howto & (RB_HALT | RB_POWEROFF))
310		HYPERVISOR_shutdown(SHUTDOWN_poweroff);
311	else
312		HYPERVISOR_shutdown(SHUTDOWN_reboot);
313}
314
315#else
316extern void xenpci_resume(void);
317
318/* HVM mode suspension. */
319static void
320xctrl_suspend()
321{
322	int suspend_cancelled;
323
324	if (DEVICE_SUSPEND(root_bus)) {
325		printf("xen_suspend: device_suspend failed\n");
326		return;
327	}
328
329	/*
330	 * Make sure we don't change cpus or switch to some other
331	 * thread. for the duration.
332	 */
333	critical_enter();
334
335	/*
336	 * Prevent any races with evtchn_interrupt() handler.
337	 */
338	irq_suspend();
339	disable_intr();
340
341	suspend_cancelled = HYPERVISOR_suspend(0);
342	if (!suspend_cancelled)
343		xenpci_resume();
344
345	/*
346	 * Re-enable interrupts and put the scheduler back to normal.
347	 */
348	enable_intr();
349	critical_exit();
350
351	/*
352	 * FreeBSD really needs to add DEVICE_SUSPEND_CANCEL or
353	 * similar.
354	 */
355	if (!suspend_cancelled)
356		DEVICE_RESUME(root_bus);
357}
358#endif
359
360static void
361xctrl_crash()
362{
363	panic("Xen directed crash");
364}
365
366static void
367xctrl_halt()
368{
369	shutdown_nice(RB_HALT);
370}
371
372/*------------------------------ Event Reception -----------------------------*/
373static void
374xctrl_on_watch_event(struct xs_watch *watch, const char **vec, unsigned int len)
375{
376	struct xctrl_shutdown_reason *reason;
377	struct xctrl_shutdown_reason *last_reason;
378	char *result;
379	int   error;
380	int   result_len;
381
382	error = xs_read(XST_NIL, "control", "shutdown",
383			&result_len, (void **)&result);
384	if (error != 0)
385		return;
386
387	reason = xctrl_shutdown_reasons;
388	last_reason = reason + NUM_ELEMENTS(xctrl_shutdown_reasons);
389	while (reason < last_reason) {
390
391		if (!strcmp(result, reason->name)) {
392			reason->handler();
393			break;
394		}
395		reason++;
396	}
397
398	free(result, M_XENSTORE);
399}
400
401/*------------------ Private Device Attachment Functions  --------------------*/
402/**
403 * \brief Identify instances of this device type in the system.
404 *
405 * \param driver  The driver performing this identify action.
406 * \param parent  The NewBus parent device for any devices this method adds.
407 */
408static void
409xctrl_identify(driver_t *driver __unused, device_t parent)
410{
411	/*
412	 * A single device instance for our driver is always present
413	 * in a system operating under Xen.
414	 */
415	BUS_ADD_CHILD(parent, 0, driver->name, 0);
416}
417
418/**
419 * \brief Probe for the existance of the Xen Control device
420 *
421 * \param dev  NewBus device_t for this Xen control instance.
422 *
423 * \return  Always returns 0 indicating success.
424 */
425static int
426xctrl_probe(device_t dev)
427{
428	device_set_desc(dev, "Xen Control Device");
429
430	return (0);
431}
432
433/**
434 * \brief Attach the Xen control device.
435 *
436 * \param dev  NewBus device_t for this Xen control instance.
437 *
438 * \return  On success, 0. Otherwise an errno value indicating the
439 *          type of failure.
440 */
441static int
442xctrl_attach(device_t dev)
443{
444	struct xctrl_softc *xctrl;
445
446	xctrl = device_get_softc(dev);
447
448	/* Activate watch */
449	xctrl->xctrl_watch.node = "control/shutdown";
450	xctrl->xctrl_watch.callback = xctrl_on_watch_event;
451	xctrl->xctrl_watch.callback_data = (uintptr_t)xctrl;
452	xs_register_watch(&xctrl->xctrl_watch);
453
454#ifndef XENHVM
455	EVENTHANDLER_REGISTER(shutdown_final, xen_pv_shutdown_final, NULL,
456			      SHUTDOWN_PRI_LAST);
457#endif
458
459	return (0);
460}
461
462/**
463 * \brief Detach the Xen control device.
464 *
465 * \param dev  NewBus device_t for this Xen control device instance.
466 *
467 * \return  On success, 0. Otherwise an errno value indicating the
468 *          type of failure.
469 */
470static int
471xctrl_detach(device_t dev)
472{
473	struct xctrl_softc *xctrl;
474
475	xctrl = device_get_softc(dev);
476
477	/* Release watch */
478	xs_unregister_watch(&xctrl->xctrl_watch);
479
480	return (0);
481}
482
483/*-------------------- Private Device Attachment Data  -----------------------*/
484static device_method_t xctrl_methods[] = {
485	/* Device interface */
486	DEVMETHOD(device_identify,	xctrl_identify),
487	DEVMETHOD(device_probe,         xctrl_probe),
488	DEVMETHOD(device_attach,        xctrl_attach),
489	DEVMETHOD(device_detach,        xctrl_detach),
490
491	{ 0, 0 }
492};
493
494DEFINE_CLASS_0(xctrl, xctrl_driver, xctrl_methods, sizeof(struct xctrl_softc));
495devclass_t xctrl_devclass;
496
497DRIVER_MODULE(xctrl, xenstore, xctrl_driver, xctrl_devclass, 0, 0);
498