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

          Line data    Source code
       1             : /*      $OpenBSD: pvbus.c,v 1.18 2018/01/18 11:43:20 mikeb Exp $        */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2015 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             : #if !defined(__i386__) && !defined(__amd64__)
      20             : #error pvbus(4) is currently only supported on i386 and amd64
      21             : #endif
      22             : 
      23             : #include <sys/param.h>
      24             : #include <sys/systm.h>
      25             : #include <sys/kernel.h>
      26             : #include <sys/malloc.h>
      27             : #include <sys/timeout.h>
      28             : #include <sys/signalvar.h>
      29             : #include <sys/syslog.h>
      30             : #include <sys/proc.h>
      31             : #include <sys/socket.h>
      32             : #include <sys/ioctl.h>
      33             : #include <sys/fcntl.h>
      34             : 
      35             : #include <machine/specialreg.h>
      36             : #include <machine/cpu.h>
      37             : #include <machine/conf.h>
      38             : #include <machine/bus.h>
      39             : #include <machine/vmmvar.h>
      40             : 
      41             : #include <dev/rndvar.h>
      42             : 
      43             : #include <dev/pv/pvvar.h>
      44             : #include <dev/pv/pvreg.h>
      45             : 
      46             : #include "vmt.h"
      47             : 
      48             : int has_hv_cpuid = 0;
      49             : 
      50             : extern char *hw_vendor;
      51             : extern void rdrand(void *);
      52             : 
      53             : int      pvbus_activate(struct device *, int);
      54             : int      pvbus_match(struct device *, void *, void *);
      55             : void     pvbus_attach(struct device *, struct device *, void *);
      56             : int      pvbus_print(void *, const char *);
      57             : int      pvbus_search(struct device *, void *, void *);
      58             : 
      59             : void     pvbus_kvm(struct pvbus_hv *);
      60             : void     pvbus_hyperv(struct pvbus_hv *);
      61             : void     pvbus_hyperv_print(struct pvbus_hv *);
      62             : void     pvbus_xen(struct pvbus_hv *);
      63             : void     pvbus_xen_print(struct pvbus_hv *);
      64             : 
      65             : int      pvbus_minor(struct pvbus_softc *, dev_t);
      66             : int      pvbusgetstr(size_t, const char *, char **);
      67             : 
      68             : struct cfattach pvbus_ca = {
      69             :         sizeof(struct pvbus_softc),
      70             :         pvbus_match,
      71             :         pvbus_attach,
      72             :         NULL,
      73             :         pvbus_activate
      74             : };
      75             : 
      76             : struct cfdriver pvbus_cd = {
      77             :         NULL,
      78             :         "pvbus",
      79             :         DV_DULL
      80             : };
      81             : 
      82             : struct pvbus_type {
      83             :         const char      *signature;
      84             :         const char      *name;
      85             :         void            (*init)(struct pvbus_hv *);
      86             :         void            (*print)(struct pvbus_hv *);
      87             : } pvbus_types[PVBUS_MAX] = {
      88             :         { "KVMKVMKVM\0\0\0",  "KVM",        pvbus_kvm },
      89             :         { "Microsoft Hv",     "Hyper-V", pvbus_hyperv, pvbus_hyperv_print },
      90             :         { "VMwareVMware",     "VMware" },
      91             :         { "XenVMMXenVMM",     "Xen",        pvbus_xen, pvbus_xen_print },
      92             :         { "bhyve bhyve ",     "bhyve" },
      93             :         { VMM_HV_SIGNATURE,     "OpenBSD" },
      94             : };
      95             : 
      96             : struct bus_dma_tag pvbus_dma_tag = {
      97             :         NULL,
      98             :         _bus_dmamap_create,
      99             :         _bus_dmamap_destroy,
     100             :         _bus_dmamap_load,
     101             :         _bus_dmamap_load_mbuf,
     102             :         _bus_dmamap_load_uio,
     103             :         _bus_dmamap_load_raw,
     104             :         _bus_dmamap_unload,
     105             :         _bus_dmamap_sync,
     106             :         _bus_dmamem_alloc,
     107             :         _bus_dmamem_alloc_range,
     108             :         _bus_dmamem_free,
     109             :         _bus_dmamem_map,
     110             :         _bus_dmamem_unmap,
     111             :         _bus_dmamem_mmap,
     112             : };
     113             : 
     114             : struct pvbus_hv pvbus_hv[PVBUS_MAX];
     115             : struct pvbus_softc *pvbus_softc;
     116             : 
     117             : int
     118           0 : pvbus_probe(void)
     119             : {
     120             :         /* Must be set in identcpu */
     121           0 :         if (!has_hv_cpuid)
     122           0 :                 return (0);
     123           0 :         return (1);
     124           0 : }
     125             : 
     126             : int
     127           0 : pvbus_match(struct device *parent, void *match, void *aux)
     128             : {
     129           0 :         const char **busname = (const char **)aux;
     130           0 :         return (strcmp(*busname, pvbus_cd.cd_name) == 0);
     131             : }
     132             : 
     133             : void
     134           0 : pvbus_attach(struct device *parent, struct device *self, void *aux)
     135             : {
     136           0 :         struct pvbus_softc *sc = (struct pvbus_softc *)self;
     137             :         int i, cnt;
     138             : 
     139           0 :         sc->pvbus_hv = pvbus_hv;
     140           0 :         pvbus_softc = sc;
     141             : 
     142           0 :         printf(":");
     143           0 :         for (i = 0, cnt = 0; i < PVBUS_MAX; i++) {
     144           0 :                 if (pvbus_hv[i].hv_base == 0)
     145             :                         continue;
     146           0 :                 if (cnt++)
     147           0 :                         printf(",");
     148           0 :                 printf(" %s", pvbus_types[i].name);
     149           0 :                 if (pvbus_types[i].print != NULL)
     150           0 :                         (pvbus_types[i].print)(&pvbus_hv[i]);
     151             :         }
     152             : 
     153           0 :         printf("\n");
     154           0 :         config_search(pvbus_search, self, sc);
     155           0 : }
     156             : 
     157             : void
     158           0 : pvbus_identify(void)
     159             : {
     160             :         struct pvbus_hv *hv;
     161             :         uint32_t reg0, base;
     162           0 :         union {
     163             :                 uint32_t        regs[3];
     164             :                 char            str[CPUID_HV_SIGNATURE_STRLEN];
     165             :         } r;
     166             :         int i, cnt;
     167             :         const char *pv_name;
     168             : 
     169           0 :         for (base = CPUID_HV_SIGNATURE_START, cnt = 0;
     170           0 :             base < CPUID_HV_SIGNATURE_END;
     171           0 :             base += CPUID_HV_SIGNATURE_STEP) {
     172           0 :                 CPUID(base, reg0, r.regs[0], r.regs[1], r.regs[2]);
     173           0 :                 for (i = 0; i < 4; i++) {
     174             :                         /*
     175             :                          * Check if first 4 chars are printable ASCII as
     176             :                          * minimal validity check
     177             :                          */
     178           0 :                         if (r.str[i] < 32 || r.str[i] > 126)
     179             :                                 goto out;
     180             :                 }
     181             : 
     182           0 :                 for (i = 0; i < PVBUS_MAX; i++) {
     183           0 :                         if (pvbus_types[i].signature == NULL ||
     184           0 :                             memcmp(pvbus_types[i].signature, r.str,
     185           0 :                             CPUID_HV_SIGNATURE_STRLEN) != 0)
     186             :                                 continue;
     187           0 :                         hv = &pvbus_hv[i];
     188           0 :                         hv->hv_base = base;
     189           0 :                         if (pvbus_types[i].init != NULL)
     190           0 :                                 (pvbus_types[i].init)(hv);
     191           0 :                         if (hw_vendor == NULL) {
     192           0 :                                 pv_name = pvbus_types[i].name;
     193             : 
     194             :                                 /*
     195             :                                  * Use the HV name as a fallback if we didn't
     196             :                                  * get the vendor name from the firmware/BIOS.
     197             :                                  */
     198           0 :                                 if ((hw_vendor = malloc(strlen(pv_name) + 1,
     199           0 :                                     M_DEVBUF, M_NOWAIT)) != NULL) {
     200           0 :                                         strlcpy(hw_vendor, pv_name,
     201           0 :                                             strlen(pv_name) + 1);
     202           0 :                                 }
     203             :                         }
     204           0 :                         cnt++;
     205           0 :                 }
     206             :         }
     207             : 
     208             :  out:
     209           0 :         if (cnt)
     210           0 :                 has_hv_cpuid = 1;
     211           0 : }
     212             : 
     213             : void
     214           0 : pvbus_init_cpu(void)
     215             : {
     216             :         int i;
     217             : 
     218           0 :         for (i = 0; i < PVBUS_MAX; i++) {
     219           0 :                 if (pvbus_hv[i].hv_base == 0)
     220             :                         continue;
     221           0 :                 if (pvbus_hv[i].hv_init_cpu != NULL)
     222           0 :                         (pvbus_hv[i].hv_init_cpu)(&pvbus_hv[i]);
     223             :         }
     224           0 : }
     225             : 
     226             : int
     227           0 : pvbus_activate(struct device *self, int act)
     228             : {
     229             :         int rv = 0;
     230             : 
     231           0 :         switch (act) {
     232             :         case DVACT_SUSPEND:
     233           0 :                 rv = config_activate_children(self, act);
     234           0 :                 break;
     235             :         case DVACT_RESUME:
     236           0 :                 rv = config_activate_children(self, act);
     237           0 :                 break;
     238             :         case DVACT_POWERDOWN:
     239           0 :                 rv = config_activate_children(self, act);
     240           0 :                 break;
     241             :         default:
     242           0 :                 rv = config_activate_children(self, act);
     243           0 :                 break;
     244             :         }
     245             : 
     246           0 :         return (rv);
     247             : }
     248             : 
     249             : int
     250           0 : pvbus_search(struct device *parent, void *arg, void *aux)
     251             : {
     252           0 :         struct pvbus_softc *sc = (struct pvbus_softc *)aux;
     253           0 :         struct cfdata           *cf = arg;
     254           0 :         struct pv_attach_args    pva;
     255             : 
     256           0 :         pva.pva_busname = cf->cf_driver->cd_name;
     257           0 :         pva.pva_hv = sc->pvbus_hv;
     258           0 :         pva.pva_dmat = &pvbus_dma_tag;
     259             : 
     260           0 :         if (cf->cf_attach->ca_match(parent, cf, &pva) > 0)
     261           0 :                 config_attach(parent, cf, &pva, pvbus_print);
     262             : 
     263           0 :         return (0);
     264           0 : }
     265             : 
     266             : int
     267           0 : pvbus_print(void *aux, const char *pnp)
     268             : {
     269           0 :         struct pv_attach_args   *pva = aux;
     270           0 :         if (pnp)
     271           0 :                 printf("%s at %s", pva->pva_busname, pnp);
     272           0 :         return (UNCONF);
     273             : }
     274             : 
     275             : void
     276           0 : pvbus_shutdown(struct device *dev)
     277             : {
     278           0 :         suspend_randomness();
     279             : 
     280           0 :         log(LOG_KERN | LOG_NOTICE, "Shutting down in response to request"
     281           0 :             " from %s host\n", dev->dv_xname);
     282           0 :         prsignal(initprocess, SIGUSR2);
     283           0 : }
     284             : 
     285             : void
     286           0 : pvbus_reboot(struct device *dev)
     287             : {
     288           0 :         suspend_randomness();
     289             : 
     290           0 :         log(LOG_KERN | LOG_NOTICE, "Rebooting in response to request"
     291           0 :             " from %s host\n", dev->dv_xname);
     292           0 :         prsignal(initprocess, SIGINT);
     293           0 : }
     294             : 
     295             : void
     296           0 : pvbus_kvm(struct pvbus_hv *hv)
     297             : {
     298             :         uint32_t regs[4];
     299             : 
     300           0 :         CPUID(hv->hv_base + CPUID_OFFSET_KVM_FEATURES,
     301             :             regs[0], regs[1], regs[2], regs[3]);
     302           0 :         hv->hv_features = regs[0];
     303           0 : }
     304             : 
     305             : void
     306           0 : pvbus_hyperv(struct pvbus_hv *hv)
     307             : {
     308             :         uint32_t regs[4];
     309             : 
     310           0 :         CPUID(hv->hv_base + CPUID_OFFSET_HYPERV_FEATURES,
     311             :             regs[0], regs[1], regs[2], regs[3]);
     312           0 :         hv->hv_features = regs[0];
     313             : 
     314           0 :         CPUID(hv->hv_base + CPUID_OFFSET_HYPERV_VERSION,
     315             :             regs[0], regs[1], regs[2], regs[3]);
     316           0 :         hv->hv_major = (regs[1] & HYPERV_VERSION_EBX_MAJOR_M) >>
     317             :             HYPERV_VERSION_EBX_MAJOR_S;
     318           0 :         hv->hv_minor = (regs[1] & HYPERV_VERSION_EBX_MINOR_M) >>
     319             :             HYPERV_VERSION_EBX_MINOR_S;
     320           0 : }
     321             : 
     322             : void
     323           0 : pvbus_hyperv_print(struct pvbus_hv *hv)
     324             : {
     325           0 :         printf(" %u.%u", hv->hv_major, hv->hv_minor);
     326           0 : }
     327             : 
     328             : void
     329           0 : pvbus_xen(struct pvbus_hv *hv)
     330             : {
     331             :         uint32_t regs[4];
     332             : 
     333           0 :         CPUID(hv->hv_base + CPUID_OFFSET_XEN_VERSION,
     334             :             regs[0], regs[1], regs[2], regs[3]);
     335           0 :         hv->hv_major = regs[0] >> XEN_VERSION_MAJOR_S;
     336           0 :         hv->hv_minor = regs[0] & XEN_VERSION_MINOR_M;
     337             : 
     338             :         /* x2apic is broken in Xen 4.2 or older */
     339           0 :         if ((hv->hv_major < 4) ||
     340           0 :             (hv->hv_major == 4 && hv->hv_minor < 3)) {
     341             :                 /* Remove CPU flag for x2apic */
     342           0 :                 cpu_ecxfeature &= ~CPUIDECX_X2APIC;
     343           0 :         }
     344           0 : }
     345             : 
     346             : void
     347           0 : pvbus_xen_print(struct pvbus_hv *hv)
     348             : {
     349           0 :         printf(" %u.%u", hv->hv_major, hv->hv_minor);
     350           0 : }
     351             : 
     352             : int
     353           0 : pvbus_minor(struct pvbus_softc *sc, dev_t dev)
     354             : {
     355             :         int hvid, cnt;
     356             :         struct pvbus_hv *hv;
     357             : 
     358           0 :         for (hvid = 0, cnt = 0; hvid < PVBUS_MAX; hvid++) {
     359           0 :                 hv = &sc->pvbus_hv[hvid];
     360           0 :                 if (hv->hv_base == 0)
     361             :                         continue;
     362           0 :                 if (minor(dev) == cnt++)
     363           0 :                         return (hvid);
     364             :         }
     365             : 
     366           0 :         return (-1);
     367           0 : }
     368             : 
     369             : int
     370           0 : pvbusopen(dev_t dev, int flags, int mode, struct proc *p)
     371             : {
     372           0 :         if (pvbus_softc == NULL)
     373           0 :                 return (ENODEV);
     374           0 :         if (pvbus_minor(pvbus_softc, dev) == -1)
     375           0 :                 return (ENXIO);
     376           0 :         return (0);
     377           0 : }
     378             : 
     379             : int
     380           0 : pvbusclose(dev_t dev, int flags, int mode, struct proc *p)
     381             : {
     382           0 :         if (pvbus_softc == NULL)
     383           0 :                 return (ENODEV);
     384           0 :         if (pvbus_minor(pvbus_softc, dev) == -1)
     385           0 :                 return (ENXIO);
     386           0 :         return (0);
     387           0 : }
     388             : 
     389             : int
     390           0 : pvbusgetstr(size_t srclen, const char *src, char **dstp)
     391             : {
     392             :         int error = 0;
     393             :         char *dst;
     394             : 
     395             :         /*
     396             :          * Reject size that is too short or obviously too long:
     397             :          * - at least one byte for the nul terminator.
     398             :          * - PAGE_SIZE is an arbitrary value, but known pv backends seem
     399             :          *   to have a hard (PAGE_SIZE - x) limit in their messaging.
     400             :          */
     401           0 :         if (srclen < 1)
     402           0 :                 return (EINVAL);
     403           0 :         else if (srclen > PAGE_SIZE)
     404           0 :                 return (ENAMETOOLONG);
     405             : 
     406           0 :         *dstp = dst = malloc(srclen + 1, M_TEMP|M_ZERO, M_WAITOK);
     407           0 :         if (src != NULL) {
     408           0 :                 error = copyin(src, dst, srclen);
     409           0 :                 dst[srclen] = '\0';
     410           0 :         }
     411             : 
     412           0 :         return (error);
     413           0 : }
     414             : 
     415             : int
     416           0 : pvbusioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
     417             : {
     418           0 :         struct pvbus_req *pvr = (struct pvbus_req *)data;
     419           0 :         struct pvbus_softc *sc = pvbus_softc;
     420           0 :         char *value = NULL, *key = NULL;
     421             :         const char *str = NULL;
     422             :         size_t valuelen = 0, keylen = 0, sz;
     423             :         int hvid, error = 0, op;
     424             :         struct pvbus_hv *hv;
     425             : 
     426           0 :         if (sc == NULL)
     427           0 :                 return (ENODEV);
     428           0 :         if ((hvid = pvbus_minor(sc, dev)) == -1)
     429           0 :                 return (ENXIO);
     430             : 
     431           0 :         switch (cmd) {
     432             :         case PVBUSIOC_KVWRITE:
     433           0 :                 if ((flags & FWRITE) == 0)
     434           0 :                         return (EPERM);
     435             :         case PVBUSIOC_KVREAD:
     436           0 :                 hv = &sc->pvbus_hv[hvid];
     437           0 :                 if (hv->hv_base == 0 || hv->hv_kvop == NULL)
     438           0 :                         return (ENXIO);
     439             :                 break;
     440             :         case PVBUSIOC_TYPE:
     441           0 :                 str = pvbus_types[hvid].name;
     442           0 :                 sz = strlen(str) + 1;
     443           0 :                 if (sz > pvr->pvr_keylen)
     444           0 :                         return (ENOMEM);
     445           0 :                 error = copyout(str, pvr->pvr_key, sz);
     446           0 :                 return (error);
     447             :         default:
     448           0 :                 return (ENOTTY);
     449             :         }
     450             : 
     451             :         str = NULL;
     452             :         op = PVBUS_KVREAD;
     453             : 
     454           0 :         switch (cmd) {
     455             :         case PVBUSIOC_KVWRITE:
     456           0 :                 str = pvr->pvr_value;
     457           0 :                 op = PVBUS_KVWRITE;
     458             : 
     459             :                 /* FALLTHROUGH */
     460             :         case PVBUSIOC_KVREAD:
     461           0 :                 keylen = pvr->pvr_keylen;
     462           0 :                 if ((error = pvbusgetstr(keylen, pvr->pvr_key, &key)) != 0)
     463             :                         break;
     464             : 
     465           0 :                 valuelen = pvr->pvr_valuelen;
     466           0 :                 if ((error = pvbusgetstr(valuelen, str, &value)) != 0)
     467             :                         break;
     468             : 
     469             :                 /* Call driver-specific callback */
     470           0 :                 if ((error = (hv->hv_kvop)(hv->hv_arg, op,
     471           0 :                     key, value, valuelen)) != 0)
     472             :                         break;
     473             : 
     474           0 :                 sz = strlen(value) + 1;
     475           0 :                 if ((error = copyout(value, pvr->pvr_value, sz)) != 0)
     476           0 :                         break;
     477             :                 break;
     478             :         default:
     479             :                 error = ENOTTY;
     480           0 :                 break;
     481             :         }
     482             : 
     483           0 :         free(key, M_TEMP, keylen + 1);
     484           0 :         free(value, M_TEMP, valuelen + 1);
     485             : 
     486           0 :         return (error);
     487           0 : }

Generated by: LCOV version 1.13