1214077Sgibbs/*- 2214077Sgibbs * Copyright (c) 2010 Justin T. Gibbs, Spectra Logic Corporation 3214077Sgibbs * All rights reserved. 4214077Sgibbs * 5214077Sgibbs * Redistribution and use in source and binary forms, with or without 6214077Sgibbs * modification, are permitted provided that the following conditions 7214077Sgibbs * are met: 8214077Sgibbs * 1. Redistributions of source code must retain the above copyright 9214077Sgibbs * notice, this list of conditions, and the following disclaimer, 10214077Sgibbs * without modification. 11214077Sgibbs * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12214077Sgibbs * substantially similar to the "NO WARRANTY" disclaimer below 13214077Sgibbs * ("Disclaimer") and any redistribution must be conditioned upon 14214077Sgibbs * including a substantially similar Disclaimer requirement for further 15214077Sgibbs * binary redistribution. 16214077Sgibbs * 17214077Sgibbs * NO WARRANTY 18214077Sgibbs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19214077Sgibbs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20214077Sgibbs * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21214077Sgibbs * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22214077Sgibbs * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23214077Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24214077Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25214077Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26214077Sgibbs * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27214077Sgibbs * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28214077Sgibbs * POSSIBILITY OF SUCH DAMAGES. 29214077Sgibbs */ 30214077Sgibbs 31214077Sgibbs/*- 32214077Sgibbs * PV suspend/resume support: 33214077Sgibbs * 34214077Sgibbs * Copyright (c) 2004 Christian Limpach. 35214077Sgibbs * Copyright (c) 2004-2006,2008 Kip Macy 36214077Sgibbs * All rights reserved. 37214077Sgibbs * 38214077Sgibbs * Redistribution and use in source and binary forms, with or without 39214077Sgibbs * modification, are permitted provided that the following conditions 40214077Sgibbs * are met: 41214077Sgibbs * 1. Redistributions of source code must retain the above copyright 42214077Sgibbs * notice, this list of conditions and the following disclaimer. 43214077Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 44214077Sgibbs * notice, this list of conditions and the following disclaimer in the 45214077Sgibbs * documentation and/or other materials provided with the distribution. 46214077Sgibbs * 3. All advertising materials mentioning features or use of this software 47214077Sgibbs * must display the following acknowledgement: 48214077Sgibbs * This product includes software developed by Christian Limpach. 49214077Sgibbs * 4. The name of the author may not be used to endorse or promote products 50214077Sgibbs * derived from this software without specific prior written permission. 51214077Sgibbs * 52214077Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 53214077Sgibbs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 54214077Sgibbs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 55214077Sgibbs * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 56214077Sgibbs * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 57214077Sgibbs * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 58214077Sgibbs * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 59214077Sgibbs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 60214077Sgibbs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 61214077Sgibbs * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62214077Sgibbs */ 63214077Sgibbs 64214077Sgibbs/*- 65214077Sgibbs * HVM suspend/resume support: 66214077Sgibbs * 67214077Sgibbs * Copyright (c) 2008 Citrix Systems, Inc. 68214077Sgibbs * All rights reserved. 69214077Sgibbs * 70214077Sgibbs * Redistribution and use in source and binary forms, with or without 71214077Sgibbs * modification, are permitted provided that the following conditions 72214077Sgibbs * are met: 73214077Sgibbs * 1. Redistributions of source code must retain the above copyright 74214077Sgibbs * notice, this list of conditions and the following disclaimer. 75214077Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 76214077Sgibbs * notice, this list of conditions and the following disclaimer in the 77214077Sgibbs * documentation and/or other materials provided with the distribution. 78214077Sgibbs * 79214077Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 80214077Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 81214077Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 82214077Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 83214077Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 84214077Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 85214077Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 86214077Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 87214077Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 88214077Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 89214077Sgibbs * SUCH DAMAGE. 90214077Sgibbs */ 91214077Sgibbs#include <sys/cdefs.h> 92214077Sgibbs__FBSDID("$FreeBSD$"); 93214077Sgibbs 94214077Sgibbs/** 95214077Sgibbs * \file control.c 96214077Sgibbs * 97214077Sgibbs * \brief Device driver to repond to control domain events that impact 98214077Sgibbs * this VM. 99214077Sgibbs */ 100214077Sgibbs 101214077Sgibbs#include <sys/param.h> 102214077Sgibbs#include <sys/systm.h> 103214077Sgibbs#include <sys/kernel.h> 104214077Sgibbs#include <sys/malloc.h> 105214077Sgibbs 106214077Sgibbs#include <sys/bio.h> 107214077Sgibbs#include <sys/bus.h> 108214077Sgibbs#include <sys/conf.h> 109214077Sgibbs#include <sys/disk.h> 110214077Sgibbs#include <sys/fcntl.h> 111214077Sgibbs#include <sys/filedesc.h> 112214077Sgibbs#include <sys/kdb.h> 113214077Sgibbs#include <sys/module.h> 114214077Sgibbs#include <sys/namei.h> 115214077Sgibbs#include <sys/proc.h> 116214077Sgibbs#include <sys/reboot.h> 117214077Sgibbs#include <sys/rman.h> 118225704Sgibbs#include <sys/sched.h> 119214077Sgibbs#include <sys/taskqueue.h> 120214077Sgibbs#include <sys/types.h> 121214077Sgibbs#include <sys/vnode.h> 122214077Sgibbs#include <sys/sched.h> 123214077Sgibbs#include <sys/smp.h> 124255726Sgibbs#include <sys/eventhandler.h> 125214077Sgibbs 126214077Sgibbs#include <geom/geom.h> 127214077Sgibbs 128214077Sgibbs#include <machine/_inttypes.h> 129255040Sgibbs#include <machine/intr_machdep.h> 130214077Sgibbs 131214077Sgibbs#include <vm/vm.h> 132214077Sgibbs#include <vm/vm_extern.h> 133214077Sgibbs#include <vm/vm_kern.h> 134214077Sgibbs 135255040Sgibbs#include <xen/xen-os.h> 136214077Sgibbs#include <xen/blkif.h> 137214077Sgibbs#include <xen/evtchn.h> 138214077Sgibbs#include <xen/gnttab.h> 139214077Sgibbs#include <xen/xen_intr.h> 140214077Sgibbs 141255726Sgibbs#ifdef XENHVM 142255726Sgibbs#include <xen/hvm.h> 143255726Sgibbs#endif 144255726Sgibbs 145214077Sgibbs#include <xen/interface/event_channel.h> 146214077Sgibbs#include <xen/interface/grant_table.h> 147214077Sgibbs 148214077Sgibbs#include <xen/xenbus/xenbusvar.h> 149214077Sgibbs 150255040Sgibbs#include <machine/xen/xenvar.h> 151255040Sgibbs#include <machine/xen/xenfunc.h> 152255040Sgibbs 153214077Sgibbs/*--------------------------- Forward Declarations --------------------------*/ 154214077Sgibbs/** Function signature for shutdown event handlers. */ 155214077Sgibbstypedef void (xctrl_shutdown_handler_t)(void); 156214077Sgibbs 157214077Sgibbsstatic xctrl_shutdown_handler_t xctrl_poweroff; 158214077Sgibbsstatic xctrl_shutdown_handler_t xctrl_reboot; 159214077Sgibbsstatic xctrl_shutdown_handler_t xctrl_suspend; 160214077Sgibbsstatic xctrl_shutdown_handler_t xctrl_crash; 161214077Sgibbs 162214077Sgibbs/*-------------------------- Private Data Structures -------------------------*/ 163214077Sgibbs/** Element type for lookup table of event name to handler. */ 164214077Sgibbsstruct xctrl_shutdown_reason { 165214077Sgibbs const char *name; 166214077Sgibbs xctrl_shutdown_handler_t *handler; 167214077Sgibbs}; 168214077Sgibbs 169214077Sgibbs/** Lookup table for shutdown event name to handler. */ 170244990Smariusstatic const struct xctrl_shutdown_reason xctrl_shutdown_reasons[] = { 171214077Sgibbs { "poweroff", xctrl_poweroff }, 172214077Sgibbs { "reboot", xctrl_reboot }, 173214077Sgibbs { "suspend", xctrl_suspend }, 174214077Sgibbs { "crash", xctrl_crash }, 175258995Sroyger { "halt", xctrl_poweroff }, 176214077Sgibbs}; 177214077Sgibbs 178214077Sgibbsstruct xctrl_softc { 179214077Sgibbs struct xs_watch xctrl_watch; 180214077Sgibbs}; 181214077Sgibbs 182214077Sgibbs/*------------------------------ Event Handlers ------------------------------*/ 183214077Sgibbsstatic void 184214077Sgibbsxctrl_poweroff() 185214077Sgibbs{ 186214077Sgibbs shutdown_nice(RB_POWEROFF|RB_HALT); 187214077Sgibbs} 188214077Sgibbs 189214077Sgibbsstatic void 190214077Sgibbsxctrl_reboot() 191214077Sgibbs{ 192214077Sgibbs shutdown_nice(0); 193214077Sgibbs} 194214077Sgibbs 195214077Sgibbs#ifndef XENHVM 196214077Sgibbsextern void xencons_suspend(void); 197214077Sgibbsextern void xencons_resume(void); 198214077Sgibbs 199214077Sgibbs/* Full PV mode suspension. */ 200214077Sgibbsstatic void 201214077Sgibbsxctrl_suspend() 202214077Sgibbs{ 203255726Sgibbs int i, j, k, fpp, suspend_cancelled; 204214077Sgibbs unsigned long max_pfn, start_info_mfn; 205214077Sgibbs 206225704Sgibbs EVENTHANDLER_INVOKE(power_suspend); 207225704Sgibbs 208214077Sgibbs#ifdef SMP 209222813Sattilio struct thread *td; 210222813Sattilio cpuset_t map; 211244990Smarius u_int cpuid; 212244990Smarius 213214077Sgibbs /* 214214077Sgibbs * Bind us to CPU 0 and stop any other VCPUs. 215214077Sgibbs */ 216222813Sattilio td = curthread; 217222813Sattilio thread_lock(td); 218222813Sattilio sched_bind(td, 0); 219222813Sattilio thread_unlock(td); 220223758Sattilio cpuid = PCPU_GET(cpuid); 221223758Sattilio KASSERT(cpuid == 0, ("xen_suspend: not running on cpu 0")); 222214077Sgibbs 223223758Sattilio map = all_cpus; 224223758Sattilio CPU_CLR(cpuid, &map); 225222813Sattilio CPU_NAND(&map, &stopped_cpus); 226222813Sattilio if (!CPU_EMPTY(&map)) 227214077Sgibbs stop_cpus(map); 228214077Sgibbs#endif 229214077Sgibbs 230225704Sgibbs /* 231225704Sgibbs * Be sure to hold Giant across DEVICE_SUSPEND/RESUME since non-MPSAFE 232225704Sgibbs * drivers need this. 233225704Sgibbs */ 234225704Sgibbs mtx_lock(&Giant); 235214077Sgibbs if (DEVICE_SUSPEND(root_bus) != 0) { 236225704Sgibbs mtx_unlock(&Giant); 237244990Smarius printf("%s: device_suspend failed\n", __func__); 238214077Sgibbs#ifdef SMP 239222813Sattilio if (!CPU_EMPTY(&map)) 240214077Sgibbs restart_cpus(map); 241214077Sgibbs#endif 242214077Sgibbs return; 243214077Sgibbs } 244225704Sgibbs mtx_unlock(&Giant); 245214077Sgibbs 246214077Sgibbs local_irq_disable(); 247214077Sgibbs 248214077Sgibbs xencons_suspend(); 249214077Sgibbs gnttab_suspend(); 250255040Sgibbs intr_suspend(); 251214077Sgibbs 252214077Sgibbs max_pfn = HYPERVISOR_shared_info->arch.max_pfn; 253214077Sgibbs 254214077Sgibbs void *shared_info = HYPERVISOR_shared_info; 255214077Sgibbs HYPERVISOR_shared_info = NULL; 256214077Sgibbs pmap_kremove((vm_offset_t) shared_info); 257214077Sgibbs PT_UPDATES_FLUSH(); 258214077Sgibbs 259214077Sgibbs xen_start_info->store_mfn = MFNTOPFN(xen_start_info->store_mfn); 260214077Sgibbs xen_start_info->console.domU.mfn = MFNTOPFN(xen_start_info->console.domU.mfn); 261214077Sgibbs 262214077Sgibbs /* 263214077Sgibbs * We'll stop somewhere inside this hypercall. When it returns, 264214077Sgibbs * we'll start resuming after the restore. 265214077Sgibbs */ 266214077Sgibbs start_info_mfn = VTOMFN(xen_start_info); 267214077Sgibbs pmap_suspend(); 268255726Sgibbs suspend_cancelled = HYPERVISOR_suspend(start_info_mfn); 269214077Sgibbs pmap_resume(); 270214077Sgibbs 271214077Sgibbs pmap_kenter_ma((vm_offset_t) shared_info, xen_start_info->shared_info); 272214077Sgibbs HYPERVISOR_shared_info = shared_info; 273214077Sgibbs 274214077Sgibbs HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = 275214077Sgibbs VTOMFN(xen_pfn_to_mfn_frame_list_list); 276214077Sgibbs 277214077Sgibbs fpp = PAGE_SIZE/sizeof(unsigned long); 278214077Sgibbs for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) { 279214077Sgibbs if ((j % fpp) == 0) { 280214077Sgibbs k++; 281214077Sgibbs xen_pfn_to_mfn_frame_list_list[k] = 282214077Sgibbs VTOMFN(xen_pfn_to_mfn_frame_list[k]); 283214077Sgibbs j = 0; 284214077Sgibbs } 285214077Sgibbs xen_pfn_to_mfn_frame_list[k][j] = 286214077Sgibbs VTOMFN(&xen_phys_machine[i]); 287214077Sgibbs } 288214077Sgibbs HYPERVISOR_shared_info->arch.max_pfn = max_pfn; 289214077Sgibbs 290214077Sgibbs gnttab_resume(); 291255726Sgibbs intr_resume(suspend_cancelled != 0); 292214077Sgibbs local_irq_enable(); 293214077Sgibbs xencons_resume(); 294214077Sgibbs 295214077Sgibbs#ifdef CONFIG_SMP 296214077Sgibbs for_each_cpu(i) 297214077Sgibbs vcpu_prepare(i); 298214077Sgibbs 299214077Sgibbs#endif 300225704Sgibbs 301214077Sgibbs /* 302214077Sgibbs * Only resume xenbus /after/ we've prepared our VCPUs; otherwise 303214077Sgibbs * the VCPU hotplug callback can race with our vcpu_prepare 304214077Sgibbs */ 305225704Sgibbs mtx_lock(&Giant); 306214077Sgibbs DEVICE_RESUME(root_bus); 307225704Sgibbs mtx_unlock(&Giant); 308214077Sgibbs 309214077Sgibbs#ifdef SMP 310214077Sgibbs thread_lock(curthread); 311214077Sgibbs sched_unbind(curthread); 312214077Sgibbs thread_unlock(curthread); 313222813Sattilio if (!CPU_EMPTY(&map)) 314214077Sgibbs restart_cpus(map); 315214077Sgibbs#endif 316225704Sgibbs EVENTHANDLER_INVOKE(power_resume); 317214077Sgibbs} 318214077Sgibbs 319214077Sgibbsstatic void 320214077Sgibbsxen_pv_shutdown_final(void *arg, int howto) 321214077Sgibbs{ 322214077Sgibbs /* 323214077Sgibbs * Inform the hypervisor that shutdown is complete. 324214077Sgibbs * This is not necessary in HVM domains since Xen 325214077Sgibbs * emulates ACPI in that mode and FreeBSD's ACPI 326214077Sgibbs * support will request this transition. 327214077Sgibbs */ 328214077Sgibbs if (howto & (RB_HALT | RB_POWEROFF)) 329214077Sgibbs HYPERVISOR_shutdown(SHUTDOWN_poweroff); 330214077Sgibbs else 331214077Sgibbs HYPERVISOR_shutdown(SHUTDOWN_reboot); 332214077Sgibbs} 333214077Sgibbs 334214077Sgibbs#else 335214077Sgibbs 336214077Sgibbs/* HVM mode suspension. */ 337214077Sgibbsstatic void 338214077Sgibbsxctrl_suspend() 339214077Sgibbs{ 340255726Sgibbs#ifdef SMP 341255726Sgibbs cpuset_t cpu_suspend_map; 342255726Sgibbs#endif 343214077Sgibbs int suspend_cancelled; 344214077Sgibbs 345225704Sgibbs EVENTHANDLER_INVOKE(power_suspend); 346225704Sgibbs 347255726Sgibbs if (smp_started) { 348255726Sgibbs thread_lock(curthread); 349255726Sgibbs sched_bind(curthread, 0); 350255726Sgibbs thread_unlock(curthread); 351255726Sgibbs } 352255726Sgibbs KASSERT((PCPU_GET(cpuid) == 0), ("Not running on CPU#0")); 353255726Sgibbs 354225704Sgibbs /* 355255726Sgibbs * Clear our XenStore node so the toolstack knows we are 356255726Sgibbs * responding to the suspend request. 357255726Sgibbs */ 358255726Sgibbs xs_write(XST_NIL, "control", "shutdown", ""); 359255726Sgibbs 360255726Sgibbs /* 361225704Sgibbs * Be sure to hold Giant across DEVICE_SUSPEND/RESUME since non-MPSAFE 362225704Sgibbs * drivers need this. 363225704Sgibbs */ 364225704Sgibbs mtx_lock(&Giant); 365244990Smarius if (DEVICE_SUSPEND(root_bus) != 0) { 366225704Sgibbs mtx_unlock(&Giant); 367244990Smarius printf("%s: device_suspend failed\n", __func__); 368214077Sgibbs return; 369214077Sgibbs } 370225704Sgibbs mtx_unlock(&Giant); 371214077Sgibbs 372255726Sgibbs#ifdef SMP 373256117Sdim CPU_ZERO(&cpu_suspend_map); /* silence gcc */ 374255726Sgibbs if (smp_started) { 375255726Sgibbs /* 376255726Sgibbs * Suspend other CPUs. This prevents IPIs while we 377255726Sgibbs * are resuming, and will allow us to reset per-cpu 378255726Sgibbs * vcpu_info on resume. 379255726Sgibbs */ 380255726Sgibbs cpu_suspend_map = all_cpus; 381255726Sgibbs CPU_CLR(PCPU_GET(cpuid), &cpu_suspend_map); 382255726Sgibbs if (!CPU_EMPTY(&cpu_suspend_map)) 383255726Sgibbs suspend_cpus(cpu_suspend_map); 384255726Sgibbs } 385255726Sgibbs#endif 386255726Sgibbs 387214077Sgibbs /* 388214077Sgibbs * Prevent any races with evtchn_interrupt() handler. 389214077Sgibbs */ 390225704Sgibbs disable_intr(); 391255040Sgibbs intr_suspend(); 392255726Sgibbs xen_hvm_suspend(); 393214077Sgibbs 394214077Sgibbs suspend_cancelled = HYPERVISOR_suspend(0); 395214077Sgibbs 396255726Sgibbs xen_hvm_resume(suspend_cancelled != 0); 397255726Sgibbs intr_resume(suspend_cancelled != 0); 398255726Sgibbs enable_intr(); 399255040Sgibbs 400214077Sgibbs /* 401255726Sgibbs * Reset grant table info. 402214077Sgibbs */ 403255726Sgibbs gnttab_resume(); 404214077Sgibbs 405255726Sgibbs#ifdef SMP 406255726Sgibbs if (smp_started && !CPU_EMPTY(&cpu_suspend_map)) { 407255726Sgibbs /* 408255726Sgibbs * Now that event channels have been initialized, 409255726Sgibbs * resume CPUs. 410255726Sgibbs */ 411255726Sgibbs resume_cpus(cpu_suspend_map); 412255726Sgibbs } 413255726Sgibbs#endif 414255726Sgibbs 415214077Sgibbs /* 416214077Sgibbs * FreeBSD really needs to add DEVICE_SUSPEND_CANCEL or 417214077Sgibbs * similar. 418214077Sgibbs */ 419225704Sgibbs mtx_lock(&Giant); 420255726Sgibbs DEVICE_RESUME(root_bus); 421225704Sgibbs mtx_unlock(&Giant); 422225704Sgibbs 423255726Sgibbs if (smp_started) { 424255726Sgibbs thread_lock(curthread); 425255726Sgibbs sched_unbind(curthread); 426255726Sgibbs thread_unlock(curthread); 427255726Sgibbs } 428255726Sgibbs 429225704Sgibbs EVENTHANDLER_INVOKE(power_resume); 430255726Sgibbs 431255726Sgibbs if (bootverbose) 432255726Sgibbs printf("System resumed after suspension\n"); 433255726Sgibbs 434214077Sgibbs} 435214077Sgibbs#endif 436214077Sgibbs 437214077Sgibbsstatic void 438214077Sgibbsxctrl_crash() 439214077Sgibbs{ 440214077Sgibbs panic("Xen directed crash"); 441214077Sgibbs} 442214077Sgibbs 443214077Sgibbs/*------------------------------ Event Reception -----------------------------*/ 444214077Sgibbsstatic void 445214077Sgibbsxctrl_on_watch_event(struct xs_watch *watch, const char **vec, unsigned int len) 446214077Sgibbs{ 447244990Smarius const struct xctrl_shutdown_reason *reason; 448244990Smarius const struct xctrl_shutdown_reason *last_reason; 449214077Sgibbs char *result; 450214077Sgibbs int error; 451214077Sgibbs int result_len; 452214077Sgibbs 453214077Sgibbs error = xs_read(XST_NIL, "control", "shutdown", 454214077Sgibbs &result_len, (void **)&result); 455214077Sgibbs if (error != 0) 456214077Sgibbs return; 457214077Sgibbs 458214077Sgibbs reason = xctrl_shutdown_reasons; 459244990Smarius last_reason = reason + nitems(xctrl_shutdown_reasons); 460214077Sgibbs while (reason < last_reason) { 461214077Sgibbs 462214077Sgibbs if (!strcmp(result, reason->name)) { 463214077Sgibbs reason->handler(); 464214077Sgibbs break; 465214077Sgibbs } 466214077Sgibbs reason++; 467214077Sgibbs } 468214077Sgibbs 469214077Sgibbs free(result, M_XENSTORE); 470214077Sgibbs} 471214077Sgibbs 472214077Sgibbs/*------------------ Private Device Attachment Functions --------------------*/ 473214077Sgibbs/** 474214077Sgibbs * \brief Identify instances of this device type in the system. 475214077Sgibbs * 476214077Sgibbs * \param driver The driver performing this identify action. 477214077Sgibbs * \param parent The NewBus parent device for any devices this method adds. 478214077Sgibbs */ 479214077Sgibbsstatic void 480214077Sgibbsxctrl_identify(driver_t *driver __unused, device_t parent) 481214077Sgibbs{ 482214077Sgibbs /* 483214077Sgibbs * A single device instance for our driver is always present 484214077Sgibbs * in a system operating under Xen. 485214077Sgibbs */ 486214077Sgibbs BUS_ADD_CHILD(parent, 0, driver->name, 0); 487214077Sgibbs} 488214077Sgibbs 489214077Sgibbs/** 490214077Sgibbs * \brief Probe for the existance of the Xen Control device 491214077Sgibbs * 492214077Sgibbs * \param dev NewBus device_t for this Xen control instance. 493214077Sgibbs * 494214077Sgibbs * \return Always returns 0 indicating success. 495214077Sgibbs */ 496214077Sgibbsstatic int 497214077Sgibbsxctrl_probe(device_t dev) 498214077Sgibbs{ 499214077Sgibbs device_set_desc(dev, "Xen Control Device"); 500214077Sgibbs 501214077Sgibbs return (0); 502214077Sgibbs} 503214077Sgibbs 504214077Sgibbs/** 505214077Sgibbs * \brief Attach the Xen control device. 506214077Sgibbs * 507214077Sgibbs * \param dev NewBus device_t for this Xen control instance. 508214077Sgibbs * 509214077Sgibbs * \return On success, 0. Otherwise an errno value indicating the 510214077Sgibbs * type of failure. 511214077Sgibbs */ 512214077Sgibbsstatic int 513214077Sgibbsxctrl_attach(device_t dev) 514214077Sgibbs{ 515214077Sgibbs struct xctrl_softc *xctrl; 516214077Sgibbs 517214077Sgibbs xctrl = device_get_softc(dev); 518214077Sgibbs 519214077Sgibbs /* Activate watch */ 520214077Sgibbs xctrl->xctrl_watch.node = "control/shutdown"; 521214077Sgibbs xctrl->xctrl_watch.callback = xctrl_on_watch_event; 522222975Sgibbs xctrl->xctrl_watch.callback_data = (uintptr_t)xctrl; 523214077Sgibbs xs_register_watch(&xctrl->xctrl_watch); 524214077Sgibbs 525214077Sgibbs#ifndef XENHVM 526214077Sgibbs EVENTHANDLER_REGISTER(shutdown_final, xen_pv_shutdown_final, NULL, 527214077Sgibbs SHUTDOWN_PRI_LAST); 528214077Sgibbs#endif 529214077Sgibbs 530214077Sgibbs return (0); 531214077Sgibbs} 532214077Sgibbs 533214077Sgibbs/** 534214077Sgibbs * \brief Detach the Xen control device. 535214077Sgibbs * 536214077Sgibbs * \param dev NewBus device_t for this Xen control device instance. 537214077Sgibbs * 538214077Sgibbs * \return On success, 0. Otherwise an errno value indicating the 539214077Sgibbs * type of failure. 540214077Sgibbs */ 541214077Sgibbsstatic int 542214077Sgibbsxctrl_detach(device_t dev) 543214077Sgibbs{ 544214077Sgibbs struct xctrl_softc *xctrl; 545214077Sgibbs 546214077Sgibbs xctrl = device_get_softc(dev); 547214077Sgibbs 548214077Sgibbs /* Release watch */ 549214077Sgibbs xs_unregister_watch(&xctrl->xctrl_watch); 550214077Sgibbs 551214077Sgibbs return (0); 552214077Sgibbs} 553214077Sgibbs 554214077Sgibbs/*-------------------- Private Device Attachment Data -----------------------*/ 555214077Sgibbsstatic device_method_t xctrl_methods[] = { 556214077Sgibbs /* Device interface */ 557214077Sgibbs DEVMETHOD(device_identify, xctrl_identify), 558214077Sgibbs DEVMETHOD(device_probe, xctrl_probe), 559214077Sgibbs DEVMETHOD(device_attach, xctrl_attach), 560214077Sgibbs DEVMETHOD(device_detach, xctrl_detach), 561214077Sgibbs 562244990Smarius DEVMETHOD_END 563214077Sgibbs}; 564214077Sgibbs 565214077SgibbsDEFINE_CLASS_0(xctrl, xctrl_driver, xctrl_methods, sizeof(struct xctrl_softc)); 566214077Sgibbsdevclass_t xctrl_devclass; 567214077Sgibbs 568244990SmariusDRIVER_MODULE(xctrl, xenstore, xctrl_driver, xctrl_devclass, NULL, NULL); 569