devvcon.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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. int nd = getdescr(vq, 1, descr);
  44. if(nd < 1)
  45. {
  46. error("virtcon: queue low");
  47. return -1;
  48. }
  49. uint8_t buf[n];
  50. if(qidx) {
  51. memmove(buf, va, n);
  52. }
  53. q2descr(vq, descr[0])->addr = PADDR(buf);
  54. q2descr(vq, descr[0])->len = n;
  55. if(qidx) {
  56. q2descr(vq, descr[0])->flags = VRING_DESC_F_WRITE;
  57. }
  58. int rc = queuedescr(vq, 1, descr);
  59. print("rwcommon rc=%d\n", rc);
  60. if(!qidx) {
  61. memmove(va, buf, n);
  62. }
  63. reldescr(vq, 1, descr);
  64. return (rc >= 0)?n:rc;
  65. }
  66. static int
  67. vcongen(Chan *c, char *d, Dirtab* dir, int i, int s, Dir *dp)
  68. {
  69. Proc *up = externup();
  70. Qid q;
  71. int t = TYPE(c->qid);
  72. int vdidx = DEV(c->qid);
  73. if(vdidx >= nvcon)
  74. error(Ebadarg);
  75. switch(t){
  76. case Qtopdir:
  77. if(s == DEVDOTDOT){
  78. q = (Qid){QID(0, Qtopdir), 0, QTDIR};
  79. snprint(up->genbuf, sizeof up->genbuf, "#%C", vcondevtab.dc);
  80. devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
  81. return 1;
  82. }
  83. return devgen(c, nil, topdir, nelem(topdir), s, dp);
  84. case Qvirtcon:
  85. if(s == DEVDOTDOT){
  86. q = (Qid){QID(0, Qtopdir), 0, QTDIR};
  87. snprint(up->genbuf, sizeof up->genbuf, "#%C", vcondevtab.dc);
  88. devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
  89. return 1;
  90. }
  91. if(s >= nvcon)
  92. return -1;
  93. snprint(up->genbuf, sizeof up->genbuf, "vcons%d", s);
  94. q = (Qid) {QID(s, Qvcpipe), 0, 0};
  95. devdir(c, q, up->genbuf, 0, eve, 0666, dp);
  96. return 1;
  97. }
  98. return -1;
  99. }
  100. static Chan*
  101. vconattach(char *spec)
  102. {
  103. return devattach(vcondevtab.dc, spec);
  104. }
  105. Walkqid*
  106. vconwalk(Chan* c, Chan *nc, char** name, int nname)
  107. {
  108. return devwalk(c, nc, name, nname, (Dirtab *)0, 0, vcongen);
  109. }
  110. static int32_t
  111. vconstat(Chan* c, uint8_t* dp, int32_t n)
  112. {
  113. return devstat(c, dp, n, (Dirtab *)0, 0L, vcongen);
  114. }
  115. static Chan*
  116. vconopen(Chan *c, int omode)
  117. {
  118. uint t = TYPE(c->qid);
  119. uint vdidx = DEV(c->qid);
  120. if(vdidx >= nvcon)
  121. error(Ebadarg);
  122. c = devopen(c, omode, (Dirtab*)0, 0, vcongen);
  123. switch(t) {
  124. default:
  125. break;
  126. }
  127. return c;
  128. }
  129. static int32_t
  130. vconread(Chan *c, void *va, int32_t n, int64_t offset)
  131. {
  132. int vdidx = DEV(c->qid);
  133. if(vdidx >= nvcon)
  134. error(Ebadarg);
  135. switch(TYPE(c->qid)) {
  136. case Qtopdir:
  137. case Qvirtcon:
  138. return devdirread(c, va, n, (Dirtab *)0, 0L, vcongen);
  139. case Qvcpipe:
  140. print("vconread dev %d addr %08p len %d\n", vdidx, va, n);
  141. return rwcommon(vcons[vdidx], va, n, 0);
  142. }
  143. return -1;
  144. }
  145. static int32_t
  146. vconwrite(Chan *c, void *va, int32_t n, int64_t offset)
  147. {
  148. int vdidx = DEV(c->qid);
  149. if(vdidx >= nvcon)
  150. error(Ebadarg);
  151. switch(TYPE(c->qid)) {
  152. case Qtopdir:
  153. case Qvirtcon:
  154. error(Eperm);
  155. return -1;
  156. case Qvcpipe:
  157. print("vconwrite dev %d addr %08p len %d\n", vdidx, va, n);
  158. return rwcommon(vcons[vdidx], va, n, 1);
  159. }
  160. return -1;
  161. }
  162. static void
  163. vconclose(Chan* c)
  164. {
  165. }
  166. static void
  167. vconinit(void)
  168. {
  169. uint32_t wantfeat(uint32_t f) {
  170. return VIRTIO_CONSOLE_F_SIZE; // We want only console size, but not multiport for simplicity
  171. }
  172. print("virtio-serial-pci initializing\n");
  173. uint32_t nvdev = getvdevnum();
  174. vcons = mallocz(nvdev * sizeof(Vqctl *), 1);
  175. if(vcons == nil) {
  176. print("no memory to allocate virtual consoles\n");
  177. return;
  178. }
  179. nvcon = getvdevsbypciid(PCI_DEVICE_ID_VIRTIO_CONSOLE, vcons, nvdev);
  180. print("virtio consoles found: %d\n", nvcon);
  181. for(int i = 0; i < nvcon; i++) {
  182. print("initializing virtual console %d\n", i);
  183. uint32_t feat = vdevfeat(vcons[i], wantfeat);
  184. print("features: 0x%08x\n", feat);
  185. struct virtio_console_config vcfg;
  186. int rc = readvdevcfg(vcons[i], &vcfg, sizeof(vcfg), 0);
  187. print("config area size %d\n", rc);
  188. print("cols=%d rows=%d ports=%d\n", vcfg.cols, vcfg.rows, vcfg.max_nr_ports);
  189. finalinitvdev(vcons[i]);
  190. }
  191. }
  192. Dev vcondevtab = {
  193. .dc = 'C',
  194. .name = "vcon",
  195. .reset = devreset,
  196. .init = vconinit,
  197. .shutdown = devshutdown,
  198. .attach = vconattach,
  199. .walk = vconwalk,
  200. .stat = vconstat,
  201. .open = vconopen,
  202. .create = devcreate,
  203. .close = vconclose,
  204. .read = vconread,
  205. .bread = devbread,
  206. .write = vconwrite,
  207. .bwrite = devbwrite,
  208. .remove = devremove,
  209. .wstat = devwstat,
  210. };