2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2016 iXsystems Inc.
7 * This software was developed by Jakub Klama <jceel@FreeBSD.org>
8 * under sponsorship from iXsystems Inc.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer
15 * in this position and unchanged.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * Copyright 2018 Joyent, Inc.
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
40 #include <sys/param.h>
41 #ifndef WITHOUT_CAPSICUM
42 #include <sys/capsicum.h>
44 #include <sys/linker_set.h>
46 #include <sys/types.h>
47 #include <sys/socket.h>
50 #ifndef WITHOUT_CAPSICUM
51 #include <capsicum_helpers.h>
72 #include "sockstream.h"
74 #define VTCON_RINGSZ 64
75 #define VTCON_MAXPORTS 16
76 #define VTCON_MAXQ (VTCON_MAXPORTS * 2 + 2)
78 #define VTCON_DEVICE_READY 0
79 #define VTCON_DEVICE_ADD 1
80 #define VTCON_DEVICE_REMOVE 2
81 #define VTCON_PORT_READY 3
82 #define VTCON_CONSOLE_PORT 4
83 #define VTCON_CONSOLE_RESIZE 5
84 #define VTCON_PORT_OPEN 6
85 #define VTCON_PORT_NAME 7
87 #define VTCON_F_SIZE 0
88 #define VTCON_F_MULTIPORT 1
89 #define VTCON_F_EMERG_WRITE 2
90 #define VTCON_S_HOSTCAPS \
91 (VTCON_F_SIZE | VTCON_F_MULTIPORT | VTCON_F_EMERG_WRITE)
93 static int pci_vtcon_debug
;
94 #define DPRINTF(params) if (pci_vtcon_debug) PRINTLN params
95 #define WPRINTF(params) PRINTLN params
97 struct pci_vtcon_softc
;
98 struct pci_vtcon_port
;
99 struct pci_vtcon_config
;
100 typedef void (pci_vtcon_cb_t
)(struct pci_vtcon_port
*, void *, struct iovec
*,
103 struct pci_vtcon_port
{
104 struct pci_vtcon_softc
* vsp_sc
;
106 const char * vsp_name
;
114 pci_vtcon_cb_t
* vsp_cb
;
117 struct pci_vtcon_sock
119 struct pci_vtcon_port
* vss_port
;
120 const char * vss_path
;
121 struct mevent
* vss_server_evp
;
122 struct mevent
* vss_conn_evp
;
128 struct pci_vtcon_softc
{
129 struct virtio_softc vsc_vs
;
130 struct vqueue_info vsc_queues
[VTCON_MAXQ
];
131 pthread_mutex_t vsc_mtx
;
133 uint64_t vsc_features
;
137 struct pci_vtcon_port vsc_control_port
;
138 struct pci_vtcon_port vsc_ports
[VTCON_MAXPORTS
];
139 struct pci_vtcon_config
*vsc_config
;
142 struct pci_vtcon_config
{
145 uint32_t max_nr_ports
;
147 } __attribute__((packed
));
149 struct pci_vtcon_control
{
153 } __attribute__((packed
));
155 struct pci_vtcon_console_resize
{
158 } __attribute__((packed
));
160 static void pci_vtcon_reset(void *);
161 static void pci_vtcon_notify_rx(void *, struct vqueue_info
*);
162 static void pci_vtcon_notify_tx(void *, struct vqueue_info
*);
163 static int pci_vtcon_cfgread(void *, int, int, uint32_t *);
164 static int pci_vtcon_cfgwrite(void *, int, int, uint32_t);
165 static void pci_vtcon_neg_features(void *, uint64_t);
166 static void pci_vtcon_sock_accept(int, enum ev_type
, void *);
167 static void pci_vtcon_sock_rx(int, enum ev_type
, void *);
168 static void pci_vtcon_sock_tx(struct pci_vtcon_port
*, void *, struct iovec
*,
170 static void pci_vtcon_control_send(struct pci_vtcon_softc
*,
171 struct pci_vtcon_control
*, const void *, size_t);
172 static void pci_vtcon_announce_port(struct pci_vtcon_port
*);
173 static void pci_vtcon_open_port(struct pci_vtcon_port
*, bool);
175 static struct virtio_consts vtcon_vi_consts
= {
177 .vc_nvq
= VTCON_MAXQ
,
178 .vc_cfgsize
= sizeof(struct pci_vtcon_config
),
179 .vc_reset
= pci_vtcon_reset
,
180 .vc_cfgread
= pci_vtcon_cfgread
,
181 .vc_cfgwrite
= pci_vtcon_cfgwrite
,
182 .vc_apply_features
= pci_vtcon_neg_features
,
183 .vc_hv_caps
= VTCON_S_HOSTCAPS
,
187 pci_vtcon_reset(void *vsc
)
189 struct pci_vtcon_softc
*sc
;
193 DPRINTF(("vtcon: device reset requested!"));
194 vi_reset_dev(&sc
->vsc_vs
);
198 pci_vtcon_neg_features(void *vsc
, uint64_t negotiated_features
)
200 struct pci_vtcon_softc
*sc
= vsc
;
202 sc
->vsc_features
= negotiated_features
;
206 pci_vtcon_cfgread(void *vsc
, int offset
, int size
, uint32_t *retval
)
208 struct pci_vtcon_softc
*sc
= vsc
;
211 ptr
= (uint8_t *)sc
->vsc_config
+ offset
;
212 memcpy(retval
, ptr
, size
);
217 pci_vtcon_cfgwrite(void *vsc __unused
, int offset __unused
, int size __unused
,
218 uint32_t val __unused
)
223 static inline struct pci_vtcon_port
*
224 pci_vtcon_vq_to_port(struct pci_vtcon_softc
*sc
, struct vqueue_info
*vq
)
226 uint16_t num
= vq
->vq_num
;
228 if (num
== 0 || num
== 1)
229 return (&sc
->vsc_ports
[0]);
231 if (num
== 2 || num
== 3)
232 return (&sc
->vsc_control_port
);
234 return (&sc
->vsc_ports
[(num
/ 2) - 1]);
237 static inline struct vqueue_info
*
238 pci_vtcon_port_to_vq(struct pci_vtcon_port
*port
, bool tx_queue
)
242 qnum
= tx_queue
? port
->vsp_txq
: port
->vsp_rxq
;
243 return (&port
->vsp_sc
->vsc_queues
[qnum
]);
246 static struct pci_vtcon_port
*
247 pci_vtcon_port_add(struct pci_vtcon_softc
*sc
, int port_id
, const char *name
,
248 pci_vtcon_cb_t
*cb
, void *arg
)
250 struct pci_vtcon_port
*port
;
252 port
= &sc
->vsc_ports
[port_id
];
253 if (port
->vsp_enabled
) {
257 port
->vsp_id
= port_id
;
259 port
->vsp_name
= name
;
263 if (port
->vsp_id
== 0) {
268 port
->vsp_txq
= (port_id
+ 1) * 2;
269 port
->vsp_rxq
= port
->vsp_txq
+ 1;
272 port
->vsp_enabled
= true;
277 pci_vtcon_sock_add(struct pci_vtcon_softc
*sc
, const char *port_name
,
280 struct pci_vtcon_sock
*sock
= NULL
;
282 struct sockaddr_un sun
;
284 /* Our compiler #defines 'sun' as '1'. Awesome. */
285 struct sockaddr_un addr
;
287 const char *name
, *path
;
290 int s
= -1, fd
= -1, error
= 0;
291 #ifndef WITHOUT_CAPSICUM
295 port
= strtol(port_name
, &cp
, 0);
296 if (*cp
!= '\0' || port
< 0 || port
>= VTCON_MAXPORTS
) {
297 EPRINTLN("vtcon: Invalid port %s", port_name
);
302 path
= get_config_value_node(nvl
, "path");
304 EPRINTLN("vtcon: required path missing for port %ld", port
);
309 sock
= calloc(1, sizeof(struct pci_vtcon_sock
));
315 s
= socket(AF_UNIX
, SOCK_STREAM
, 0);
322 pathcopy
= strdup(path
);
323 if (pathcopy
== NULL
) {
328 fd
= open(dirname(pathcopy
), O_RDONLY
| O_DIRECTORY
);
335 sun
.sun_family
= AF_UNIX
;
336 sun
.sun_len
= sizeof(struct sockaddr_un
);
337 strcpy(pathcopy
, path
);
338 strlcpy(sun
.sun_path
, basename(pathcopy
), sizeof(sun
.sun_path
));
341 if (bindat(fd
, s
, (struct sockaddr
*)&sun
, sun
.sun_len
) < 0) {
345 #else /* __FreeBSD__ */
346 /* Do a simple bind rather than the FreeBSD bindat() */
347 pathcopy
= (char *)path
;
348 addr
.sun_family
= AF_UNIX
;
349 (void) strlcpy(addr
.sun_path
, pathcopy
, sizeof (addr
.sun_path
));
350 if (bind(fd
, (struct sockaddr
*)&addr
, sizeof (addr
)) < 0) {
354 #endif /* __FreeBSD__ */
356 if (fcntl(s
, F_SETFL
, O_NONBLOCK
) < 0) {
361 if (listen(s
, 1) < 0) {
366 #ifndef WITHOUT_CAPSICUM
367 cap_rights_init(&rights
, CAP_ACCEPT
, CAP_EVENT
, CAP_READ
, CAP_WRITE
);
368 if (caph_rights_limit(s
, &rights
) == -1)
369 errx(EX_OSERR
, "Unable to apply rights for sandbox");
372 name
= get_config_value_node(nvl
, "name");
374 EPRINTLN("vtcon: required name missing for port %ld", port
);
378 sock
->vss_port
= pci_vtcon_port_add(sc
, port
, name
, pci_vtcon_sock_tx
, sock
);
379 if (sock
->vss_port
== NULL
) {
384 sock
->vss_open
= false;
385 sock
->vss_conn_fd
= -1;
386 sock
->vss_server_fd
= s
;
387 sock
->vss_server_evp
= mevent_add(s
, EVF_READ
, pci_vtcon_sock_accept
,
390 if (sock
->vss_server_evp
== NULL
) {
409 pci_vtcon_sock_accept(int fd __unused
, enum ev_type t __unused
, void *arg
)
411 struct pci_vtcon_sock
*sock
= (struct pci_vtcon_sock
*)arg
;
414 s
= accept(sock
->vss_server_fd
, NULL
, NULL
);
418 if (sock
->vss_open
) {
423 sock
->vss_open
= true;
424 sock
->vss_conn_fd
= s
;
425 sock
->vss_conn_evp
= mevent_add(s
, EVF_READ
, pci_vtcon_sock_rx
, sock
);
427 pci_vtcon_open_port(sock
->vss_port
, true);
431 pci_vtcon_sock_rx(int fd __unused
, enum ev_type t __unused
, void *arg
)
433 struct pci_vtcon_port
*port
;
434 struct pci_vtcon_sock
*sock
= (struct pci_vtcon_sock
*)arg
;
435 struct vqueue_info
*vq
;
438 static char dummybuf
[2048];
441 port
= sock
->vss_port
;
442 vq
= pci_vtcon_port_to_vq(port
, true);
444 if (!sock
->vss_open
|| !port
->vsp_rx_ready
) {
445 len
= read(sock
->vss_conn_fd
, dummybuf
, sizeof(dummybuf
));
452 if (!vq_has_descs(vq
)) {
453 len
= read(sock
->vss_conn_fd
, dummybuf
, sizeof(dummybuf
));
462 n
= vq_getchain(vq
, &iov
, 1, &req
);
464 len
= readv(sock
->vss_conn_fd
, &iov
, n
);
466 if (len
== 0 || (len
< 0 && errno
== EWOULDBLOCK
)) {
475 vq_relchain(vq
, req
.idx
, len
);
476 } while (vq_has_descs(vq
));
481 mevent_delete_close(sock
->vss_conn_evp
);
482 sock
->vss_conn_fd
= -1;
483 sock
->vss_open
= false;
487 pci_vtcon_sock_tx(struct pci_vtcon_port
*port __unused
, void *arg __unused
,
488 struct iovec
*iov
, int niov
)
490 struct pci_vtcon_sock
*sock
;
497 sock
= (struct pci_vtcon_sock
*)arg
;
499 if (sock
->vss_conn_fd
== -1)
502 for (i
= 0; i
< niov
; i
++) {
503 ret
= stream_write(sock
->vss_conn_fd
, iov
[i
].iov_base
,
510 mevent_delete_close(sock
->vss_conn_evp
);
511 sock
->vss_conn_fd
= -1;
512 sock
->vss_open
= false;
517 pci_vtcon_control_tx(struct pci_vtcon_port
*port
, void *arg __unused
,
518 struct iovec
*iov
, int niov
)
520 struct pci_vtcon_softc
*sc
;
521 struct pci_vtcon_port
*tmp
;
522 struct pci_vtcon_control resp
, *ctrl
;
528 ctrl
= (struct pci_vtcon_control
*)iov
->iov_base
;
530 switch (ctrl
->event
) {
531 case VTCON_DEVICE_READY
:
532 sc
->vsc_ready
= true;
533 /* set port ready events for registered ports */
534 for (i
= 0; i
< VTCON_MAXPORTS
; i
++) {
535 tmp
= &sc
->vsc_ports
[i
];
536 if (tmp
->vsp_enabled
)
537 pci_vtcon_announce_port(tmp
);
540 pci_vtcon_open_port(tmp
, true);
544 case VTCON_PORT_READY
:
545 tmp
= &sc
->vsc_ports
[ctrl
->id
];
546 if (ctrl
->id
>= VTCON_MAXPORTS
|| !tmp
->vsp_enabled
) {
547 WPRINTF(("VTCON_PORT_READY event for unknown port %d",
552 if (tmp
->vsp_console
) {
553 resp
.event
= VTCON_CONSOLE_PORT
;
556 pci_vtcon_control_send(sc
, &resp
, NULL
, 0);
563 pci_vtcon_announce_port(struct pci_vtcon_port
*port
)
565 struct pci_vtcon_control event
;
567 event
.id
= port
->vsp_id
;
568 event
.event
= VTCON_DEVICE_ADD
;
570 pci_vtcon_control_send(port
->vsp_sc
, &event
, NULL
, 0);
572 event
.event
= VTCON_PORT_NAME
;
573 pci_vtcon_control_send(port
->vsp_sc
, &event
, port
->vsp_name
,
574 strlen(port
->vsp_name
));
578 pci_vtcon_open_port(struct pci_vtcon_port
*port
, bool open
)
580 struct pci_vtcon_control event
;
582 if (!port
->vsp_sc
->vsc_ready
) {
583 port
->vsp_open
= true;
587 event
.id
= port
->vsp_id
;
588 event
.event
= VTCON_PORT_OPEN
;
589 event
.value
= (int)open
;
590 pci_vtcon_control_send(port
->vsp_sc
, &event
, NULL
, 0);
594 pci_vtcon_control_send(struct pci_vtcon_softc
*sc
,
595 struct pci_vtcon_control
*ctrl
, const void *payload
, size_t len
)
597 struct vqueue_info
*vq
;
602 vq
= pci_vtcon_port_to_vq(&sc
->vsc_control_port
, true);
604 if (!vq_has_descs(vq
))
607 n
= vq_getchain(vq
, &iov
, 1, &req
);
610 memcpy(iov
.iov_base
, ctrl
, sizeof(struct pci_vtcon_control
));
611 if (payload
!= NULL
&& len
> 0)
612 memcpy((uint8_t *)iov
.iov_base
+
613 sizeof(struct pci_vtcon_control
), payload
, len
);
615 vq_relchain(vq
, req
.idx
, sizeof(struct pci_vtcon_control
) + len
);
621 pci_vtcon_notify_tx(void *vsc
, struct vqueue_info
*vq
)
623 struct pci_vtcon_softc
*sc
;
624 struct pci_vtcon_port
*port
;
630 port
= pci_vtcon_vq_to_port(sc
, vq
);
632 while (vq_has_descs(vq
)) {
633 n
= vq_getchain(vq
, iov
, 1, &req
);
636 port
->vsp_cb(port
, port
->vsp_arg
, iov
, 1);
639 * Release this chain and handle more
641 vq_relchain(vq
, req
.idx
, 0);
643 vq_endchains(vq
, 1); /* Generate interrupt if appropriate. */
647 pci_vtcon_notify_rx(void *vsc
, struct vqueue_info
*vq
)
649 struct pci_vtcon_softc
*sc
;
650 struct pci_vtcon_port
*port
;
653 port
= pci_vtcon_vq_to_port(sc
, vq
);
655 if (!port
->vsp_rx_ready
) {
656 port
->vsp_rx_ready
= 1;
662 * Each console device has a "port" node which contains nodes for
663 * each port. Ports are numbered starting at 0.
666 pci_vtcon_legacy_config_port(nvlist_t
*nvl
, int port
, char *opt
)
669 char node_name
[sizeof("XX")];
672 name
= strsep(&opt
, "=");
675 EPRINTLN("vtcon: port %s requires a path", name
);
678 if (port
>= VTCON_MAXPORTS
) {
679 EPRINTLN("vtcon: too many ports");
682 snprintf(node_name
, sizeof(node_name
), "%d", port
);
683 port_nvl
= create_relative_config_node(nvl
, node_name
);
684 set_config_value_node(port_nvl
, "name", name
);
685 set_config_value_node(port_nvl
, "path", path
);
690 pci_vtcon_legacy_config(nvlist_t
*nvl
, const char *opts
)
692 char *opt
, *str
, *tofree
;
696 ports_nvl
= create_relative_config_node(nvl
, "port");
697 tofree
= str
= strdup(opts
);
700 while ((opt
= strsep(&str
, ",")) != NULL
) {
701 error
= pci_vtcon_legacy_config_port(ports_nvl
, port
, opt
);
711 pci_vtcon_init(struct vmctx
*ctx __unused
, struct pci_devinst
*pi
,
714 struct pci_vtcon_softc
*sc
;
718 sc
= calloc(1, sizeof(struct pci_vtcon_softc
));
719 sc
->vsc_config
= calloc(1, sizeof(struct pci_vtcon_config
));
720 sc
->vsc_config
->max_nr_ports
= VTCON_MAXPORTS
;
721 sc
->vsc_config
->cols
= 80;
722 sc
->vsc_config
->rows
= 25;
724 pthread_mutex_init(&sc
->vsc_mtx
, NULL
);
726 vi_softc_linkup(&sc
->vsc_vs
, &vtcon_vi_consts
, sc
, pi
, sc
->vsc_queues
);
727 sc
->vsc_vs
.vs_mtx
= &sc
->vsc_mtx
;
729 for (i
= 0; i
< VTCON_MAXQ
; i
++) {
730 sc
->vsc_queues
[i
].vq_qsize
= VTCON_RINGSZ
;
731 sc
->vsc_queues
[i
].vq_notify
= i
% 2 == 0
732 ? pci_vtcon_notify_rx
733 : pci_vtcon_notify_tx
;
736 /* initialize config space */
737 pci_set_cfgdata16(pi
, PCIR_DEVICE
, VIRTIO_DEV_CONSOLE
);
738 pci_set_cfgdata16(pi
, PCIR_VENDOR
, VIRTIO_VENDOR
);
739 pci_set_cfgdata8(pi
, PCIR_CLASS
, PCIC_SIMPLECOMM
);
740 pci_set_cfgdata16(pi
, PCIR_SUBDEV_0
, VIRTIO_ID_CONSOLE
);
741 pci_set_cfgdata16(pi
, PCIR_SUBVEND_0
, VIRTIO_VENDOR
);
743 if (vi_intr_init(&sc
->vsc_vs
, 1, fbsdrun_virtio_msix()))
745 vi_set_io_bar(&sc
->vsc_vs
, 0);
747 /* create control port */
748 sc
->vsc_control_port
.vsp_sc
= sc
;
749 sc
->vsc_control_port
.vsp_txq
= 2;
750 sc
->vsc_control_port
.vsp_rxq
= 3;
751 sc
->vsc_control_port
.vsp_cb
= pci_vtcon_control_tx
;
752 sc
->vsc_control_port
.vsp_enabled
= true;
754 ports_nvl
= find_relative_config_node(nvl
, "port");
755 if (ports_nvl
!= NULL
) {
761 while ((name
= nvlist_next(ports_nvl
, &type
, &cookie
)) !=
763 if (type
!= NV_TYPE_NVLIST
)
766 if (pci_vtcon_sock_add(sc
, name
,
767 nvlist_get_nvlist(ports_nvl
, name
)) < 0) {
768 EPRINTLN("cannot create port %s: %s",
769 name
, strerror(errno
));
778 static const struct pci_devemu pci_de_vcon
= {
779 .pe_emu
= "virtio-console",
780 .pe_init
= pci_vtcon_init
,
781 .pe_barwrite
= vi_pci_write
,
782 .pe_barread
= vi_pci_read
,
783 .pe_legacy_config
= pci_vtcon_legacy_config
,
785 PCI_EMUL_SET(pci_de_vcon
);