pvbus.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /* $OpenBSD: pvbus.c,v 1.5 2015/07/29 17:08:46 mikeb Exp $ */
  2. /*
  3. * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #if !defined(__i386__) && !defined(__amd64__)
  18. #error pvbus(4) is currently only supported on i386 and amd64
  19. #endif
  20. #include <sys/param.h>
  21. #include <sys/systm.h>
  22. #include <sys/kernel.h>
  23. #include <sys/malloc.h>
  24. #include <sys/timeout.h>
  25. #include <sys/signalvar.h>
  26. #include <sys/syslog.h>
  27. #include <sys/proc.h>
  28. #include <sys/socket.h>
  29. #include <machine/specialreg.h>
  30. #include <dev/rndvar.h>
  31. #include <dev/pv/pvvar.h>
  32. #include <dev/pv/pvreg.h>
  33. #include "vmt.h"
  34. int has_hv_cpuid = 0;
  35. extern void rdrand(void *);
  36. int pvbus_activate(struct device *, int);
  37. int pvbus_match(struct device *, void *, void *);
  38. void pvbus_attach(struct device *, struct device *, void *);
  39. int pvbus_print(void *, const char *);
  40. int pvbus_search(struct device *, void *, void *);
  41. void pvbus_kvm(struct pvbus_softc *, struct pvbus_hv *);
  42. void pvbus_hyperv(struct pvbus_softc *, struct pvbus_hv *);
  43. void pvbus_xen(struct pvbus_softc *, struct pvbus_hv *);
  44. struct cfattach pvbus_ca = {
  45. sizeof(struct pvbus_softc),
  46. pvbus_match,
  47. pvbus_attach,
  48. NULL,
  49. pvbus_activate
  50. };
  51. struct cfdriver pvbus_cd = {
  52. NULL,
  53. "pvbus",
  54. DV_DULL
  55. };
  56. struct pvbus_type {
  57. const char *signature;
  58. const char *name;
  59. void (*init)(struct pvbus_softc *, struct pvbus_hv *);
  60. } pvbus_types[PVBUS_MAX] = {
  61. { "KVMKVMKVM\0\0\0", "KVM", pvbus_kvm },
  62. { "Microsoft Hv", "Hyper-V", pvbus_hyperv },
  63. { "VMwareVMware", "VMware", NULL },
  64. { "XenVMMXenVMM", "Xen", pvbus_xen },
  65. { "bhyve bhyve ", "bhyve", NULL }
  66. };
  67. int
  68. pvbus_probe(void)
  69. {
  70. /* Must be set in identcpu */
  71. if (!has_hv_cpuid)
  72. return (0);
  73. return (1);
  74. }
  75. int
  76. pvbus_match(struct device *parent, void *match, void *aux)
  77. {
  78. const char **busname = (const char **)aux;
  79. return (strcmp(*busname, pvbus_cd.cd_name) == 0);
  80. }
  81. void
  82. pvbus_attach(struct device *parent, struct device *self, void *aux)
  83. {
  84. struct pvbus_softc *sc = (struct pvbus_softc *)self;
  85. struct pvbus_hv *hv;
  86. uint32_t reg0, base;
  87. union {
  88. uint32_t regs[3];
  89. char str[CPUID_HV_SIGNATURE_STRLEN];
  90. } r;
  91. int i, cnt;
  92. printf(":");
  93. for (base = CPUID_HV_SIGNATURE_START, cnt = 0;
  94. base < CPUID_HV_SIGNATURE_END;
  95. base += CPUID_HV_SIGNATURE_STEP) {
  96. CPUID(base, reg0, r.regs[0], r.regs[1], r.regs[2]);
  97. for (i = 0; i < 4; i++) {
  98. /*
  99. * Check if first 4 chars are printable ASCII as
  100. * minimal validity check
  101. */
  102. if (r.str[i] < 32 || r.str[i] > 126)
  103. goto out;
  104. }
  105. for (i = 0; i < PVBUS_MAX; i++) {
  106. if (memcmp(pvbus_types[i].signature, r.str,
  107. CPUID_HV_SIGNATURE_STRLEN) != 0)
  108. continue;
  109. hv = &sc->pvbus_hv[i];
  110. hv->hv_base = base;
  111. if (cnt++)
  112. printf(",");
  113. printf(" %s", pvbus_types[i].name);
  114. if (pvbus_types[i].init != NULL)
  115. (pvbus_types[i].init)(sc, hv);
  116. }
  117. }
  118. out:
  119. printf("\n");
  120. config_search(pvbus_search, self, sc);
  121. }
  122. int
  123. pvbus_activate(struct device *self, int act)
  124. {
  125. int rv = 0;
  126. switch (act) {
  127. case DVACT_SUSPEND:
  128. rv = config_activate_children(self, act);
  129. break;
  130. case DVACT_RESUME:
  131. rv = config_activate_children(self, act);
  132. break;
  133. case DVACT_POWERDOWN:
  134. rv = config_activate_children(self, act);
  135. break;
  136. default:
  137. rv = config_activate_children(self, act);
  138. break;
  139. }
  140. return (rv);
  141. }
  142. int
  143. pvbus_search(struct device *parent, void *arg, void *aux)
  144. {
  145. struct pvbus_softc *sc = (struct pvbus_softc *)aux;
  146. struct cfdata *cf = arg;
  147. struct pv_attach_args pva;
  148. pva.pva_busname = cf->cf_driver->cd_name;
  149. pva.pva_hv = sc->pvbus_hv;
  150. if (cf->cf_attach->ca_match(parent, cf, &pva) > 0)
  151. config_attach(parent, cf, &pva, pvbus_print);
  152. return (0);
  153. }
  154. int
  155. pvbus_print(void *aux, const char *pnp)
  156. {
  157. struct pv_attach_args *pva = aux;
  158. if (pnp)
  159. printf("%s at %s", pva->pva_busname, pnp);
  160. return (UNCONF);
  161. }
  162. void
  163. pvbus_kvm(struct pvbus_softc *sc, struct pvbus_hv *hv)
  164. {
  165. uint32_t regs[4];
  166. CPUID(hv->hv_base + CPUID_OFFSET_KVM_FEATURES,
  167. regs[0], regs[1], regs[2], regs[3]);
  168. hv->hv_features = regs[0];
  169. }
  170. void
  171. pvbus_hyperv(struct pvbus_softc *sc, struct pvbus_hv *hv)
  172. {
  173. uint32_t regs[4];
  174. CPUID(hv->hv_base + CPUID_OFFSET_HYPERV_FEATURES,
  175. regs[0], regs[1], regs[2], regs[3]);
  176. hv->hv_features = regs[0];
  177. CPUID(hv->hv_base + CPUID_OFFSET_HYPERV_VERSION,
  178. regs[0], regs[1], regs[2], regs[3]);
  179. hv->hv_version = regs[1];
  180. printf(" %u.%u.%u",
  181. (regs[1] & HYPERV_VERSION_EBX_MAJOR_M) >>
  182. HYPERV_VERSION_EBX_MAJOR_S,
  183. (regs[1] & HYPERV_VERSION_EBX_MINOR_M) >>
  184. HYPERV_VERSION_EBX_MINOR_S,
  185. regs[0]);
  186. }
  187. void
  188. pvbus_xen(struct pvbus_softc *sc, struct pvbus_hv *hv)
  189. {
  190. uint32_t regs[4];
  191. CPUID(hv->hv_base + CPUID_OFFSET_XEN_VERSION,
  192. regs[0], regs[1], regs[2], regs[3]);
  193. hv->hv_version = regs[0];
  194. printf(" %u.%u", regs[0] >> XEN_VERSION_MAJOR_S,
  195. regs[0] & XEN_VERSION_MINOR_M);
  196. }