devvcon.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. * This file is part of the Harvey operating system. It is subject to the
  3. * license terms of the GNU GPL v2 in LICENSE.gpl found in the top-level
  4. * directory of this distribution and at http://www.gnu.org/licenses/gpl-2.0.txt
  5. *
  6. * No part of Harvey operating system, including this file, may be copied,
  7. * modified, propagated, or distributed except according to the terms
  8. * contained in the LICENSE.gpl file.
  9. */
  10. // devvcon.c ('#C'): a virtual console (virtio-serial-pci) driver.
  11. #include "u.h"
  12. #include "../port/lib.h"
  13. #include "mem.h"
  14. #include "dat.h"
  15. #include "fns.h"
  16. #include "io.h"
  17. #include "../port/error.h"
  18. #include "virtio_ring.h"
  19. #include "virtio_config.h"
  20. #include "virtio_console.h"
  21. #include "virtio_pci.h"
  22. #include "virtio_lib.h"
  23. enum
  24. {
  25. Qtopdir = 0, // top directory
  26. Qvirtcon, // virtcon directory under the top where all consoles live
  27. Qvcpipe, // console pipe for reading/writing
  28. };
  29. static Dirtab topdir[] = {
  30. ".", { Qtopdir, 0, QTDIR }, 0, DMDIR|0555,
  31. "virtcon", { Qvirtcon, 0, QTDIR }, 0, DMDIR|0555,
  32. };
  33. extern Dev vcondevtab;
  34. // Array of defined virtconsoles and their number
  35. static uint32_t nvcon;
  36. static Vqctl **vcons;
  37. // Read-write common code
  38. static int
  39. rwcommon(Vqctl *d, void *va, int32_t n, int qidx)
  40. {
  41. uint16_t descr[1];
  42. Virtq *vq = d->vqs[qidx];
  43. if(vq == nil) {
  44. error("virtcon: no virtqueue");
  45. }
  46. int nd = getdescr(vq, 1, descr);
  47. if(nd < 1)
  48. {
  49. error("virtcon: queue low");
  50. return -1;
  51. }
  52. uint8_t *buf = malloc(n);
  53. if(buf==nil) {
  54. error("devvcon: no memory to allocate the exchange buffer");
  55. return -1;
  56. }
  57. if(qidx) {
  58. memmove(buf, va, n);
  59. }
  60. q2descr(vq, descr[0])->addr = PADDR(buf);
  61. q2descr(vq, descr[0])->len = n;
  62. if(!qidx) {
  63. q2descr(vq, descr[0])->flags = VRING_DESC_F_WRITE;
  64. }
  65. int rc = queuedescr(vq, 1, descr);
  66. if(!qidx) {
  67. memmove(va, buf, n);
  68. }
  69. reldescr(vq, 1, descr);
  70. free(buf);
  71. return (rc >= 0)?n:rc;
  72. }
  73. static int
  74. vcongen(Chan *c, char *d, Dirtab* dir, int i, int s, Dir *dp)
  75. {
  76. Proc *up = externup();
  77. Qid q;
  78. int t = TYPE(c->qid);
  79. int vdidx = DEV(c->qid);
  80. if(vdidx >= nvcon)
  81. error(Ebadarg);
  82. switch(t){
  83. case Qtopdir:
  84. if(s == DEVDOTDOT){
  85. q = (Qid){QID(0, Qtopdir), 0, QTDIR};
  86. snprint(up->genbuf, sizeof up->genbuf, "#%C", vcondevtab.dc);
  87. devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
  88. return 1;
  89. }
  90. return devgen(c, nil, topdir, nelem(topdir), s, dp);
  91. case Qvirtcon:
  92. if(s == DEVDOTDOT){
  93. q = (Qid){QID(0, Qtopdir), 0, QTDIR};
  94. snprint(up->genbuf, sizeof up->genbuf, "#%C", vcondevtab.dc);
  95. devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
  96. return 1;
  97. }
  98. if(s >= nvcon)
  99. return -1;
  100. snprint(up->genbuf, sizeof up->genbuf, vcons[s]->devname);
  101. q = (Qid) {QID(s, Qvcpipe), 0, 0};
  102. devdir(c, q, up->genbuf, 0, eve, 0666, dp);
  103. return 1;
  104. }
  105. return -1;
  106. }
  107. static Chan*
  108. vconattach(char *spec)
  109. {
  110. return devattach(vcondevtab.dc, spec);
  111. }
  112. Walkqid*
  113. vconwalk(Chan* c, Chan *nc, char** name, int nname)
  114. {
  115. return devwalk(c, nc, name, nname, (Dirtab *)0, 0, vcongen);
  116. }
  117. static int32_t
  118. vconstat(Chan* c, uint8_t* dp, int32_t n)
  119. {
  120. return devstat(c, dp, n, (Dirtab *)0, 0L, vcongen);
  121. }
  122. static Chan*
  123. vconopen(Chan *c, int omode)
  124. {
  125. uint t = TYPE(c->qid);
  126. uint vdidx = DEV(c->qid);
  127. if(vdidx >= nvcon)
  128. error(Ebadarg);
  129. c = devopen(c, omode, (Dirtab*)0, 0, vcongen);
  130. switch(t) {
  131. default:
  132. break;
  133. }
  134. return c;
  135. }
  136. static int32_t
  137. vconread(Chan *c, void *va, int32_t n, int64_t offset)
  138. {
  139. int vdidx = DEV(c->qid);
  140. if(vdidx >= nvcon)
  141. error(Ebadarg);
  142. switch(TYPE(c->qid)) {
  143. case Qtopdir:
  144. case Qvirtcon:
  145. return devdirread(c, va, n, (Dirtab *)0, 0L, vcongen);
  146. case Qvcpipe:
  147. return rwcommon(vcons[vdidx], va, n, 0);
  148. }
  149. return -1;
  150. }
  151. static int32_t
  152. vconwrite(Chan *c, void *va, int32_t n, int64_t offset)
  153. {
  154. int vdidx = DEV(c->qid);
  155. if(vdidx >= nvcon)
  156. error(Ebadarg);
  157. switch(TYPE(c->qid)) {
  158. case Qtopdir:
  159. case Qvirtcon:
  160. error(Eperm);
  161. return -1;
  162. case Qvcpipe:
  163. return rwcommon(vcons[vdidx], va, n, 1);
  164. }
  165. return -1;
  166. }
  167. static void
  168. vconclose(Chan* c)
  169. {
  170. }
  171. static uint32_t
  172. wantfeat(uint32_t f) {
  173. return VIRTIO_CONSOLE_F_SIZE; // We want only console size, but not multiport for simplicity
  174. }
  175. static void
  176. vconinit(void)
  177. {
  178. uint32_t nvdev;
  179. print("virtio-serial-pci initializing\n");
  180. nvdev = getvdevnum();
  181. if(nvdev <= 0)
  182. return;
  183. vcons = mallocz(nvdev * sizeof(Vqctl *), 1);
  184. if(vcons == nil) {
  185. print("no memory to allocate virtual consoles\n");
  186. return;
  187. }
  188. nvcon = 0;
  189. nvcon = getvdevsbypciid(PCI_DEVICE_ID_VIRTIO_CONSOLE, vcons, nvdev);
  190. print("virtio consoles found: %d\n", nvcon);
  191. for(int i = 0; i < nvcon; i++) {
  192. print("initializing virtual console %d\n", i);
  193. uint32_t feat = vdevfeat(vcons[i], wantfeat);
  194. print("features: 0x%08x\n", feat);
  195. struct virtio_console_config vcfg;
  196. int rc = readvdevcfg(vcons[i], &vcfg, sizeof(vcfg), 0);
  197. print("config area size %d\n", rc);
  198. print("cols=%d rows=%d ports=%d\n", vcfg.cols, vcfg.rows, vcfg.max_nr_ports);
  199. finalinitvdev(vcons[i]);
  200. }
  201. }
  202. Dev vcondevtab = {
  203. .dc = 'C',
  204. .name = "vcon",
  205. .reset = devreset,
  206. .init = vconinit,
  207. .shutdown = devshutdown,
  208. .attach = vconattach,
  209. .walk = vconwalk,
  210. .stat = vconstat,
  211. .open = vconopen,
  212. .create = devcreate,
  213. .close = vconclose,
  214. .read = vconread,
  215. .bread = devbread,
  216. .write = vconwrite,
  217. .bwrite = devbwrite,
  218. .remove = devremove,
  219. .wstat = devwstat,
  220. };