LCOV - code coverage report
Current view: top level - dev/pv - vmmci.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 80 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 6 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: vmmci.c,v 1.3 2017/05/02 09:50:38 mlarkin Exp $       */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2017 Reyk Floeter <reyk@openbsd.org>
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : #include <sys/param.h>
      20             : #include <sys/systm.h>
      21             : #include <sys/kernel.h>
      22             : #include <sys/timeout.h>
      23             : #include <sys/signalvar.h>
      24             : #include <sys/syslog.h>
      25             : #include <sys/device.h>
      26             : #include <sys/pool.h>
      27             : #include <sys/proc.h>
      28             : 
      29             : #include <machine/bus.h>
      30             : 
      31             : #include <dev/pv/virtioreg.h>
      32             : #include <dev/pv/virtiovar.h>
      33             : #include <dev/pv/pvvar.h>
      34             : #include <dev/rndvar.h>
      35             : 
      36             : enum vmmci_cmd {
      37             :         VMMCI_NONE = 0,
      38             :         VMMCI_SHUTDOWN,
      39             :         VMMCI_REBOOT,
      40             :         VMMCI_SYNCRTC,
      41             : };
      42             : 
      43             : struct vmmci_softc {
      44             :         struct device            sc_dev;
      45             :         struct virtio_softc     *sc_virtio;
      46             :         enum vmmci_cmd           sc_cmd;
      47             :         unsigned int             sc_interval;
      48             :         struct ksensordev        sc_sensordev;
      49             :         struct ksensor           sc_sensor;
      50             :         struct timeout           sc_tick;
      51             : };
      52             : 
      53             : int     vmmci_match(struct device *, void *, void *);
      54             : void    vmmci_attach(struct device *, struct device *, void *);
      55             : int     vmmci_activate(struct device *, int);
      56             : 
      57             : int     vmmci_config_change(struct virtio_softc *);
      58             : void    vmmci_tick(void *);
      59             : void    vmmci_tick_hook(struct device *);
      60             : 
      61             : struct cfattach vmmci_ca = {
      62             :         sizeof(struct vmmci_softc),
      63             :         vmmci_match,
      64             :         vmmci_attach,
      65             :         NULL,
      66             :         vmmci_activate
      67             : };
      68             : 
      69             : /* Configuration registers */
      70             : #define VMMCI_CONFIG_COMMAND    0
      71             : #define VMMCI_CONFIG_TIME_SEC   4
      72             : #define VMMCI_CONFIG_TIME_USEC  12
      73             : 
      74             : /* Feature bits */
      75             : #define VMMCI_F_TIMESYNC        (1<<0)
      76             : #define VMMCI_F_ACK             (1<<1)
      77             : #define VMMCI_F_SYNCRTC         (1<<2)
      78             : 
      79             : struct cfdriver vmmci_cd = {
      80             :         NULL, "vmmci", DV_DULL
      81             : };
      82             : 
      83             : int
      84           0 : vmmci_match(struct device *parent, void *match, void *aux)
      85             : {
      86           0 :         struct virtio_softc *va = aux;
      87           0 :         if (va->sc_childdevid == PCI_PRODUCT_VIRTIO_VMMCI)
      88           0 :                 return (1);
      89           0 :         return (0);
      90           0 : }
      91             : 
      92             : void
      93           0 : vmmci_attach(struct device *parent, struct device *self, void *aux)
      94             : {
      95           0 :         struct vmmci_softc *sc = (struct vmmci_softc *)self;
      96           0 :         struct virtio_softc *vsc = (struct virtio_softc *)parent;
      97             :         uint32_t features;
      98             : 
      99           0 :         if (vsc->sc_child != NULL)
     100           0 :                 panic("already attached to something else");
     101             : 
     102           0 :         vsc->sc_child = self;
     103           0 :         vsc->sc_nvqs = 0;
     104           0 :         vsc->sc_config_change = vmmci_config_change;
     105           0 :         vsc->sc_ipl = IPL_NET;
     106           0 :         sc->sc_virtio = vsc;
     107             : 
     108             :         features = VMMCI_F_TIMESYNC | VMMCI_F_ACK | VMMCI_F_SYNCRTC;
     109           0 :         features = virtio_negotiate_features(vsc, features, NULL);
     110             : 
     111           0 :         if (features & VMMCI_F_TIMESYNC) {
     112           0 :                 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
     113             :                     sizeof(sc->sc_sensordev.xname));
     114           0 :                 sc->sc_sensor.type = SENSOR_TIMEDELTA;
     115           0 :                 sc->sc_sensor.status = SENSOR_S_UNKNOWN;
     116           0 :                 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
     117           0 :                 sensordev_install(&sc->sc_sensordev);
     118             : 
     119           0 :                 config_mountroot(self, vmmci_tick_hook);
     120           0 :         }
     121             : 
     122           0 :         printf("\n");
     123           0 : }
     124             : 
     125             : int
     126           0 : vmmci_activate(struct device *self, int act)
     127             : {
     128           0 :         struct vmmci_softc      *sc = (struct vmmci_softc *)self;
     129           0 :         struct virtio_softc     *vsc = sc->sc_virtio;
     130             : 
     131           0 :         if ((vsc->sc_features & VMMCI_F_ACK) == 0)
     132           0 :                 return (0);
     133             : 
     134           0 :         switch (act) {
     135             :         case DVACT_POWERDOWN:
     136           0 :                 printf("%s: powerdown\n", sc->sc_dev.dv_xname);
     137             : 
     138             :                 /*
     139             :                  * Tell the host that we are shutting down.  The host will
     140             :                  * start a timer and kill our VM if we didn't reboot before
     141             :                  * expiration.  This avoids being stuck in the
     142             :                  * "Please press any key to reboot" handler on RB_HALT;
     143             :                  * without hooking into the MD code directly.
     144             :                  */
     145           0 :                 virtio_write_device_config_4(vsc, VMMCI_CONFIG_COMMAND,
     146             :                     VMMCI_SHUTDOWN);
     147           0 :                 break;
     148             :         default:
     149             :                 break;
     150             :         }
     151           0 :         return (0);
     152           0 : }
     153             : 
     154             : int
     155           0 : vmmci_config_change(struct virtio_softc *vsc)
     156             : {
     157           0 :         struct vmmci_softc      *sc = (struct vmmci_softc *)vsc->sc_child;
     158             :         uint32_t                 cmd;
     159             : 
     160             :         /* Check for command */
     161           0 :         cmd = virtio_read_device_config_4(vsc, VMMCI_CONFIG_COMMAND);
     162           0 :         if (cmd == sc->sc_cmd)
     163           0 :                 return (0);
     164           0 :         sc->sc_cmd = cmd;
     165             : 
     166           0 :         switch (cmd) {
     167             :         case VMMCI_NONE:
     168             :                 /* no action */
     169             :                 break;
     170             :         case VMMCI_SHUTDOWN:
     171           0 :                 pvbus_shutdown(&sc->sc_dev);
     172           0 :                 break;
     173             :         case VMMCI_REBOOT:
     174           0 :                 pvbus_reboot(&sc->sc_dev);
     175           0 :                 break;
     176             :         case VMMCI_SYNCRTC:
     177           0 :                 inittodr(time_second);
     178           0 :                 sc->sc_cmd = VMMCI_NONE;
     179           0 :                 break;  
     180             :         default:
     181           0 :                 printf("%s: invalid command %d\n", sc->sc_dev.dv_xname, cmd);
     182             :                 cmd = VMMCI_NONE;               
     183           0 :                 break;
     184             :         }
     185             : 
     186           0 :         if ((cmd != VMMCI_NONE) &&
     187           0 :             (vsc->sc_features & VMMCI_F_ACK))
     188           0 :                 virtio_write_device_config_4(vsc, VMMCI_CONFIG_COMMAND, cmd);
     189             : 
     190           0 :         return (1);
     191           0 : }
     192             : 
     193             : void
     194           0 : vmmci_tick(void *arg)
     195             : {
     196           0 :         struct vmmci_softc      *sc = arg;
     197           0 :         struct virtio_softc     *vsc = sc->sc_virtio;
     198           0 :         struct timeval          *guest = &sc->sc_sensor.tv;
     199             :         struct timeval           host, diff;
     200             : 
     201           0 :         microtime(guest);
     202             : 
     203             :         /* Update time delta sensor */
     204           0 :         host.tv_sec = virtio_read_device_config_8(vsc, VMMCI_CONFIG_TIME_SEC);
     205           0 :         host.tv_usec = virtio_read_device_config_8(vsc, VMMCI_CONFIG_TIME_USEC);
     206             : 
     207           0 :         if (host.tv_usec > 0) {
     208           0 :                 timersub(guest, &host, &diff);
     209             : 
     210           0 :                 sc->sc_sensor.value = (uint64_t)diff.tv_sec * 1000000000LL +
     211           0 :                     (uint64_t)diff.tv_usec * 1000LL;
     212           0 :                 sc->sc_sensor.status = SENSOR_S_OK;
     213           0 :         } else
     214           0 :                 sc->sc_sensor.status = SENSOR_S_UNKNOWN;
     215             : 
     216           0 :         timeout_add_sec(&sc->sc_tick, 15);
     217           0 : }
     218             : 
     219             : void
     220           0 : vmmci_tick_hook(struct device *self)
     221             : {
     222           0 :         struct vmmci_softc      *sc = (struct vmmci_softc *)self;
     223             : 
     224           0 :         timeout_set(&sc->sc_tick, vmmci_tick, sc);
     225           0 :         vmmci_tick(sc);
     226           0 : }

Generated by: LCOV version 1.13