devvcon.c 5.1 KB

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