113ee8ddeSJakub Wojciech Klama /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3ce80faa4SMarcelo Araujo *
413ee8ddeSJakub Wojciech Klama * Copyright (c) 2016 iXsystems Inc.
513ee8ddeSJakub Wojciech Klama * All rights reserved.
613ee8ddeSJakub Wojciech Klama *
713ee8ddeSJakub Wojciech Klama * This software was developed by Jakub Klama <jceel@FreeBSD.org>
813ee8ddeSJakub Wojciech Klama * under sponsorship from iXsystems Inc.
913ee8ddeSJakub Wojciech Klama *
1013ee8ddeSJakub Wojciech Klama * Redistribution and use in source and binary forms, with or without
1113ee8ddeSJakub Wojciech Klama * modification, are permitted provided that the following conditions
1213ee8ddeSJakub Wojciech Klama * are met:
1313ee8ddeSJakub Wojciech Klama * 1. Redistributions of source code must retain the above copyright
1413ee8ddeSJakub Wojciech Klama * notice, this list of conditions and the following disclaimer
1513ee8ddeSJakub Wojciech Klama * in this position and unchanged.
1613ee8ddeSJakub Wojciech Klama * 2. Redistributions in binary form must reproduce the above copyright
1713ee8ddeSJakub Wojciech Klama * notice, this list of conditions and the following disclaimer in the
1813ee8ddeSJakub Wojciech Klama * documentation and/or other materials provided with the distribution.
1913ee8ddeSJakub Wojciech Klama *
2013ee8ddeSJakub Wojciech Klama * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2113ee8ddeSJakub Wojciech Klama * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2213ee8ddeSJakub Wojciech Klama * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2313ee8ddeSJakub Wojciech Klama * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2413ee8ddeSJakub Wojciech Klama * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2513ee8ddeSJakub Wojciech Klama * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2613ee8ddeSJakub Wojciech Klama * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2713ee8ddeSJakub Wojciech Klama * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2813ee8ddeSJakub Wojciech Klama * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2913ee8ddeSJakub Wojciech Klama * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3013ee8ddeSJakub Wojciech Klama * SUCH DAMAGE.
3113ee8ddeSJakub Wojciech Klama */
3213ee8ddeSJakub Wojciech Klama
3313ee8ddeSJakub Wojciech Klama #include <sys/param.h>
3400ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
3500ef17beSBartek Rutkowski #include <sys/capsicum.h>
3600ef17beSBartek Rutkowski #endif
3713ee8ddeSJakub Wojciech Klama #include <sys/linker_set.h>
3813ee8ddeSJakub Wojciech Klama #include <sys/uio.h>
3913ee8ddeSJakub Wojciech Klama #include <sys/types.h>
4013ee8ddeSJakub Wojciech Klama #include <sys/socket.h>
4113ee8ddeSJakub Wojciech Klama #include <sys/un.h>
4213ee8ddeSJakub Wojciech Klama
43abfa3c39SMarcelo Araujo #ifndef WITHOUT_CAPSICUM
44abfa3c39SMarcelo Araujo #include <capsicum_helpers.h>
45abfa3c39SMarcelo Araujo #endif
4600ef17beSBartek Rutkowski #include <err.h>
4713ee8ddeSJakub Wojciech Klama #include <errno.h>
4813ee8ddeSJakub Wojciech Klama #include <fcntl.h>
4913ee8ddeSJakub Wojciech Klama #include <stdio.h>
5013ee8ddeSJakub Wojciech Klama #include <stdlib.h>
5113ee8ddeSJakub Wojciech Klama #include <stdbool.h>
5213ee8ddeSJakub Wojciech Klama #include <string.h>
5313ee8ddeSJakub Wojciech Klama #include <unistd.h>
5413ee8ddeSJakub Wojciech Klama #include <assert.h>
5513ee8ddeSJakub Wojciech Klama #include <pthread.h>
5613ee8ddeSJakub Wojciech Klama #include <libgen.h>
5700ef17beSBartek Rutkowski #include <sysexits.h>
5813ee8ddeSJakub Wojciech Klama
5913ee8ddeSJakub Wojciech Klama #include "bhyverun.h"
60621b5090SJohn Baldwin #include "config.h"
61332eff95SVincenzo Maffione #include "debug.h"
6213ee8ddeSJakub Wojciech Klama #include "pci_emul.h"
6313ee8ddeSJakub Wojciech Klama #include "virtio.h"
6413ee8ddeSJakub Wojciech Klama #include "mevent.h"
65d286418eSJakub Wojciech Klama #include "sockstream.h"
6613ee8ddeSJakub Wojciech Klama
6713ee8ddeSJakub Wojciech Klama #define VTCON_RINGSZ 64
6813ee8ddeSJakub Wojciech Klama #define VTCON_MAXPORTS 16
6913ee8ddeSJakub Wojciech Klama #define VTCON_MAXQ (VTCON_MAXPORTS * 2 + 2)
7013ee8ddeSJakub Wojciech Klama
7113ee8ddeSJakub Wojciech Klama #define VTCON_DEVICE_READY 0
7213ee8ddeSJakub Wojciech Klama #define VTCON_DEVICE_ADD 1
7313ee8ddeSJakub Wojciech Klama #define VTCON_DEVICE_REMOVE 2
7413ee8ddeSJakub Wojciech Klama #define VTCON_PORT_READY 3
7513ee8ddeSJakub Wojciech Klama #define VTCON_CONSOLE_PORT 4
7613ee8ddeSJakub Wojciech Klama #define VTCON_CONSOLE_RESIZE 5
7713ee8ddeSJakub Wojciech Klama #define VTCON_PORT_OPEN 6
7813ee8ddeSJakub Wojciech Klama #define VTCON_PORT_NAME 7
7913ee8ddeSJakub Wojciech Klama
8013ee8ddeSJakub Wojciech Klama #define VTCON_F_SIZE 0
8113ee8ddeSJakub Wojciech Klama #define VTCON_F_MULTIPORT 1
8213ee8ddeSJakub Wojciech Klama #define VTCON_F_EMERG_WRITE 2
8313ee8ddeSJakub Wojciech Klama #define VTCON_S_HOSTCAPS \
8413ee8ddeSJakub Wojciech Klama (VTCON_F_SIZE | VTCON_F_MULTIPORT | VTCON_F_EMERG_WRITE)
8513ee8ddeSJakub Wojciech Klama
8613ee8ddeSJakub Wojciech Klama static int pci_vtcon_debug;
87332eff95SVincenzo Maffione #define DPRINTF(params) if (pci_vtcon_debug) PRINTLN params
88332eff95SVincenzo Maffione #define WPRINTF(params) PRINTLN params
8913ee8ddeSJakub Wojciech Klama
9013ee8ddeSJakub Wojciech Klama struct pci_vtcon_softc;
9113ee8ddeSJakub Wojciech Klama struct pci_vtcon_port;
9213ee8ddeSJakub Wojciech Klama struct pci_vtcon_config;
9313ee8ddeSJakub Wojciech Klama typedef void (pci_vtcon_cb_t)(struct pci_vtcon_port *, void *, struct iovec *,
9413ee8ddeSJakub Wojciech Klama int);
9513ee8ddeSJakub Wojciech Klama
9613ee8ddeSJakub Wojciech Klama struct pci_vtcon_port {
9713ee8ddeSJakub Wojciech Klama struct pci_vtcon_softc * vsp_sc;
9813ee8ddeSJakub Wojciech Klama int vsp_id;
9913ee8ddeSJakub Wojciech Klama const char * vsp_name;
10013ee8ddeSJakub Wojciech Klama bool vsp_enabled;
10113ee8ddeSJakub Wojciech Klama bool vsp_console;
10213ee8ddeSJakub Wojciech Klama bool vsp_rx_ready;
103962094d5SJakub Wojciech Klama bool vsp_open;
10413ee8ddeSJakub Wojciech Klama int vsp_rxq;
10513ee8ddeSJakub Wojciech Klama int vsp_txq;
10613ee8ddeSJakub Wojciech Klama void * vsp_arg;
10713ee8ddeSJakub Wojciech Klama pci_vtcon_cb_t * vsp_cb;
10813ee8ddeSJakub Wojciech Klama };
10913ee8ddeSJakub Wojciech Klama
11013ee8ddeSJakub Wojciech Klama struct pci_vtcon_sock
11113ee8ddeSJakub Wojciech Klama {
11213ee8ddeSJakub Wojciech Klama struct pci_vtcon_port * vss_port;
11313ee8ddeSJakub Wojciech Klama const char * vss_path;
11413ee8ddeSJakub Wojciech Klama struct mevent * vss_server_evp;
11513ee8ddeSJakub Wojciech Klama struct mevent * vss_conn_evp;
11613ee8ddeSJakub Wojciech Klama int vss_server_fd;
11713ee8ddeSJakub Wojciech Klama int vss_conn_fd;
11813ee8ddeSJakub Wojciech Klama bool vss_open;
11913ee8ddeSJakub Wojciech Klama };
12013ee8ddeSJakub Wojciech Klama
12113ee8ddeSJakub Wojciech Klama struct pci_vtcon_softc {
12213ee8ddeSJakub Wojciech Klama struct virtio_softc vsc_vs;
12313ee8ddeSJakub Wojciech Klama struct vqueue_info vsc_queues[VTCON_MAXQ];
12413ee8ddeSJakub Wojciech Klama pthread_mutex_t vsc_mtx;
12513ee8ddeSJakub Wojciech Klama uint64_t vsc_cfg;
12613ee8ddeSJakub Wojciech Klama uint64_t vsc_features;
12713ee8ddeSJakub Wojciech Klama char * vsc_rootdir;
12813ee8ddeSJakub Wojciech Klama int vsc_kq;
129962094d5SJakub Wojciech Klama bool vsc_ready;
13013ee8ddeSJakub Wojciech Klama struct pci_vtcon_port vsc_control_port;
13113ee8ddeSJakub Wojciech Klama struct pci_vtcon_port vsc_ports[VTCON_MAXPORTS];
13213ee8ddeSJakub Wojciech Klama struct pci_vtcon_config *vsc_config;
13313ee8ddeSJakub Wojciech Klama };
13413ee8ddeSJakub Wojciech Klama
13513ee8ddeSJakub Wojciech Klama struct pci_vtcon_config {
13613ee8ddeSJakub Wojciech Klama uint16_t cols;
13713ee8ddeSJakub Wojciech Klama uint16_t rows;
13813ee8ddeSJakub Wojciech Klama uint32_t max_nr_ports;
13913ee8ddeSJakub Wojciech Klama uint32_t emerg_wr;
14013ee8ddeSJakub Wojciech Klama } __attribute__((packed));
14113ee8ddeSJakub Wojciech Klama
14213ee8ddeSJakub Wojciech Klama struct pci_vtcon_control {
14313ee8ddeSJakub Wojciech Klama uint32_t id;
14413ee8ddeSJakub Wojciech Klama uint16_t event;
14513ee8ddeSJakub Wojciech Klama uint16_t value;
14613ee8ddeSJakub Wojciech Klama } __attribute__((packed));
14713ee8ddeSJakub Wojciech Klama
14813ee8ddeSJakub Wojciech Klama struct pci_vtcon_console_resize {
14913ee8ddeSJakub Wojciech Klama uint16_t cols;
15013ee8ddeSJakub Wojciech Klama uint16_t rows;
15113ee8ddeSJakub Wojciech Klama } __attribute__((packed));
15213ee8ddeSJakub Wojciech Klama
15313ee8ddeSJakub Wojciech Klama static void pci_vtcon_reset(void *);
15413ee8ddeSJakub Wojciech Klama static void pci_vtcon_notify_rx(void *, struct vqueue_info *);
15513ee8ddeSJakub Wojciech Klama static void pci_vtcon_notify_tx(void *, struct vqueue_info *);
15613ee8ddeSJakub Wojciech Klama static int pci_vtcon_cfgread(void *, int, int, uint32_t *);
15713ee8ddeSJakub Wojciech Klama static int pci_vtcon_cfgwrite(void *, int, int, uint32_t);
15813ee8ddeSJakub Wojciech Klama static void pci_vtcon_neg_features(void *, uint64_t);
15913ee8ddeSJakub Wojciech Klama static void pci_vtcon_sock_accept(int, enum ev_type, void *);
16013ee8ddeSJakub Wojciech Klama static void pci_vtcon_sock_rx(int, enum ev_type, void *);
16113ee8ddeSJakub Wojciech Klama static void pci_vtcon_sock_tx(struct pci_vtcon_port *, void *, struct iovec *,
16213ee8ddeSJakub Wojciech Klama int);
16313ee8ddeSJakub Wojciech Klama static void pci_vtcon_control_send(struct pci_vtcon_softc *,
16413ee8ddeSJakub Wojciech Klama struct pci_vtcon_control *, const void *, size_t);
16513ee8ddeSJakub Wojciech Klama static void pci_vtcon_announce_port(struct pci_vtcon_port *);
16613ee8ddeSJakub Wojciech Klama static void pci_vtcon_open_port(struct pci_vtcon_port *, bool);
16713ee8ddeSJakub Wojciech Klama
16813ee8ddeSJakub Wojciech Klama static struct virtio_consts vtcon_vi_consts = {
1696cb26162SMark Johnston .vc_name = "vtcon",
1706cb26162SMark Johnston .vc_nvq = VTCON_MAXQ,
1716cb26162SMark Johnston .vc_cfgsize = sizeof(struct pci_vtcon_config),
1726cb26162SMark Johnston .vc_reset = pci_vtcon_reset,
1736cb26162SMark Johnston .vc_cfgread = pci_vtcon_cfgread,
1746cb26162SMark Johnston .vc_cfgwrite = pci_vtcon_cfgwrite,
1756cb26162SMark Johnston .vc_apply_features = pci_vtcon_neg_features,
1766cb26162SMark Johnston .vc_hv_caps = VTCON_S_HOSTCAPS,
17713ee8ddeSJakub Wojciech Klama };
17813ee8ddeSJakub Wojciech Klama
17913ee8ddeSJakub Wojciech Klama static void
pci_vtcon_reset(void * vsc)18013ee8ddeSJakub Wojciech Klama pci_vtcon_reset(void *vsc)
18113ee8ddeSJakub Wojciech Klama {
18213ee8ddeSJakub Wojciech Klama struct pci_vtcon_softc *sc;
18313ee8ddeSJakub Wojciech Klama
18413ee8ddeSJakub Wojciech Klama sc = vsc;
18513ee8ddeSJakub Wojciech Klama
186332eff95SVincenzo Maffione DPRINTF(("vtcon: device reset requested!"));
18713ee8ddeSJakub Wojciech Klama vi_reset_dev(&sc->vsc_vs);
18813ee8ddeSJakub Wojciech Klama }
18913ee8ddeSJakub Wojciech Klama
19013ee8ddeSJakub Wojciech Klama static void
pci_vtcon_neg_features(void * vsc,uint64_t negotiated_features)19113ee8ddeSJakub Wojciech Klama pci_vtcon_neg_features(void *vsc, uint64_t negotiated_features)
19213ee8ddeSJakub Wojciech Klama {
19313ee8ddeSJakub Wojciech Klama struct pci_vtcon_softc *sc = vsc;
19413ee8ddeSJakub Wojciech Klama
19513ee8ddeSJakub Wojciech Klama sc->vsc_features = negotiated_features;
19613ee8ddeSJakub Wojciech Klama }
19713ee8ddeSJakub Wojciech Klama
19813ee8ddeSJakub Wojciech Klama static int
pci_vtcon_cfgread(void * vsc,int offset,int size,uint32_t * retval)19913ee8ddeSJakub Wojciech Klama pci_vtcon_cfgread(void *vsc, int offset, int size, uint32_t *retval)
20013ee8ddeSJakub Wojciech Klama {
20113ee8ddeSJakub Wojciech Klama struct pci_vtcon_softc *sc = vsc;
20213ee8ddeSJakub Wojciech Klama void *ptr;
20313ee8ddeSJakub Wojciech Klama
20413ee8ddeSJakub Wojciech Klama ptr = (uint8_t *)sc->vsc_config + offset;
20513ee8ddeSJakub Wojciech Klama memcpy(retval, ptr, size);
20613ee8ddeSJakub Wojciech Klama return (0);
20713ee8ddeSJakub Wojciech Klama }
20813ee8ddeSJakub Wojciech Klama
20913ee8ddeSJakub Wojciech Klama static int
pci_vtcon_cfgwrite(void * vsc __unused,int offset __unused,int size __unused,uint32_t val __unused)21098d920d9SMark Johnston pci_vtcon_cfgwrite(void *vsc __unused, int offset __unused, int size __unused,
21198d920d9SMark Johnston uint32_t val __unused)
21213ee8ddeSJakub Wojciech Klama {
21313ee8ddeSJakub Wojciech Klama return (0);
21413ee8ddeSJakub Wojciech Klama }
21513ee8ddeSJakub Wojciech Klama
21613ee8ddeSJakub Wojciech Klama static inline struct pci_vtcon_port *
pci_vtcon_vq_to_port(struct pci_vtcon_softc * sc,struct vqueue_info * vq)21713ee8ddeSJakub Wojciech Klama pci_vtcon_vq_to_port(struct pci_vtcon_softc *sc, struct vqueue_info *vq)
21813ee8ddeSJakub Wojciech Klama {
21913ee8ddeSJakub Wojciech Klama uint16_t num = vq->vq_num;
22013ee8ddeSJakub Wojciech Klama
22113ee8ddeSJakub Wojciech Klama if (num == 0 || num == 1)
22213ee8ddeSJakub Wojciech Klama return (&sc->vsc_ports[0]);
22313ee8ddeSJakub Wojciech Klama
22413ee8ddeSJakub Wojciech Klama if (num == 2 || num == 3)
22513ee8ddeSJakub Wojciech Klama return (&sc->vsc_control_port);
22613ee8ddeSJakub Wojciech Klama
22713ee8ddeSJakub Wojciech Klama return (&sc->vsc_ports[(num / 2) - 1]);
22813ee8ddeSJakub Wojciech Klama }
22913ee8ddeSJakub Wojciech Klama
23013ee8ddeSJakub Wojciech Klama static inline struct vqueue_info *
pci_vtcon_port_to_vq(struct pci_vtcon_port * port,bool tx_queue)23113ee8ddeSJakub Wojciech Klama pci_vtcon_port_to_vq(struct pci_vtcon_port *port, bool tx_queue)
23213ee8ddeSJakub Wojciech Klama {
23313ee8ddeSJakub Wojciech Klama int qnum;
23413ee8ddeSJakub Wojciech Klama
23513ee8ddeSJakub Wojciech Klama qnum = tx_queue ? port->vsp_txq : port->vsp_rxq;
23613ee8ddeSJakub Wojciech Klama return (&port->vsp_sc->vsc_queues[qnum]);
23713ee8ddeSJakub Wojciech Klama }
23813ee8ddeSJakub Wojciech Klama
23913ee8ddeSJakub Wojciech Klama static struct pci_vtcon_port *
pci_vtcon_port_add(struct pci_vtcon_softc * sc,int port_id,const char * name,pci_vtcon_cb_t * cb,void * arg)240621b5090SJohn Baldwin pci_vtcon_port_add(struct pci_vtcon_softc *sc, int port_id, const char *name,
24113ee8ddeSJakub Wojciech Klama pci_vtcon_cb_t *cb, void *arg)
24213ee8ddeSJakub Wojciech Klama {
24313ee8ddeSJakub Wojciech Klama struct pci_vtcon_port *port;
24413ee8ddeSJakub Wojciech Klama
245621b5090SJohn Baldwin port = &sc->vsc_ports[port_id];
246621b5090SJohn Baldwin if (port->vsp_enabled) {
24713ee8ddeSJakub Wojciech Klama errno = EBUSY;
24813ee8ddeSJakub Wojciech Klama return (NULL);
24913ee8ddeSJakub Wojciech Klama }
250621b5090SJohn Baldwin port->vsp_id = port_id;
25113ee8ddeSJakub Wojciech Klama port->vsp_sc = sc;
25213ee8ddeSJakub Wojciech Klama port->vsp_name = name;
25313ee8ddeSJakub Wojciech Klama port->vsp_cb = cb;
25413ee8ddeSJakub Wojciech Klama port->vsp_arg = arg;
25513ee8ddeSJakub Wojciech Klama
25613ee8ddeSJakub Wojciech Klama if (port->vsp_id == 0) {
25713ee8ddeSJakub Wojciech Klama /* port0 */
25813ee8ddeSJakub Wojciech Klama port->vsp_txq = 0;
25913ee8ddeSJakub Wojciech Klama port->vsp_rxq = 1;
26013ee8ddeSJakub Wojciech Klama } else {
261621b5090SJohn Baldwin port->vsp_txq = (port_id + 1) * 2;
26213ee8ddeSJakub Wojciech Klama port->vsp_rxq = port->vsp_txq + 1;
26313ee8ddeSJakub Wojciech Klama }
26413ee8ddeSJakub Wojciech Klama
26513ee8ddeSJakub Wojciech Klama port->vsp_enabled = true;
26613ee8ddeSJakub Wojciech Klama return (port);
26713ee8ddeSJakub Wojciech Klama }
26813ee8ddeSJakub Wojciech Klama
26913ee8ddeSJakub Wojciech Klama static int
pci_vtcon_sock_add(struct pci_vtcon_softc * sc,const char * port_name,const nvlist_t * nvl)270621b5090SJohn Baldwin pci_vtcon_sock_add(struct pci_vtcon_softc *sc, const char *port_name,
271621b5090SJohn Baldwin const nvlist_t *nvl)
27213ee8ddeSJakub Wojciech Klama {
273bc928800SJohn Baldwin struct pci_vtcon_sock *sock = NULL;
27413ee8ddeSJakub Wojciech Klama struct sockaddr_un sun;
275621b5090SJohn Baldwin const char *name, *path;
276621b5090SJohn Baldwin char *cp, *pathcopy;
277621b5090SJohn Baldwin long port;
27813ee8ddeSJakub Wojciech Klama int s = -1, fd = -1, error = 0;
27900ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
28000ef17beSBartek Rutkowski cap_rights_t rights;
28100ef17beSBartek Rutkowski #endif
28213ee8ddeSJakub Wojciech Klama
283621b5090SJohn Baldwin port = strtol(port_name, &cp, 0);
284621b5090SJohn Baldwin if (*cp != '\0' || port < 0 || port >= VTCON_MAXPORTS) {
285621b5090SJohn Baldwin EPRINTLN("vtcon: Invalid port %s", port_name);
286621b5090SJohn Baldwin error = -1;
287621b5090SJohn Baldwin goto out;
288621b5090SJohn Baldwin }
289621b5090SJohn Baldwin
290621b5090SJohn Baldwin path = get_config_value_node(nvl, "path");
291621b5090SJohn Baldwin if (path == NULL) {
292621b5090SJohn Baldwin EPRINTLN("vtcon: required path missing for port %ld", port);
293621b5090SJohn Baldwin error = -1;
294621b5090SJohn Baldwin goto out;
295621b5090SJohn Baldwin }
296621b5090SJohn Baldwin
29713ee8ddeSJakub Wojciech Klama sock = calloc(1, sizeof(struct pci_vtcon_sock));
29813ee8ddeSJakub Wojciech Klama if (sock == NULL) {
29913ee8ddeSJakub Wojciech Klama error = -1;
30013ee8ddeSJakub Wojciech Klama goto out;
30113ee8ddeSJakub Wojciech Klama }
30213ee8ddeSJakub Wojciech Klama
30313ee8ddeSJakub Wojciech Klama s = socket(AF_UNIX, SOCK_STREAM, 0);
30413ee8ddeSJakub Wojciech Klama if (s < 0) {
30513ee8ddeSJakub Wojciech Klama error = -1;
30613ee8ddeSJakub Wojciech Klama goto out;
30713ee8ddeSJakub Wojciech Klama }
30813ee8ddeSJakub Wojciech Klama
309ecc28863SEd Schouten pathcopy = strdup(path);
310ecc28863SEd Schouten if (pathcopy == NULL) {
311ecc28863SEd Schouten error = -1;
312ecc28863SEd Schouten goto out;
313ecc28863SEd Schouten }
314ecc28863SEd Schouten
315ecc28863SEd Schouten fd = open(dirname(pathcopy), O_RDONLY | O_DIRECTORY);
31613ee8ddeSJakub Wojciech Klama if (fd < 0) {
317ecc28863SEd Schouten free(pathcopy);
31813ee8ddeSJakub Wojciech Klama error = -1;
31913ee8ddeSJakub Wojciech Klama goto out;
32013ee8ddeSJakub Wojciech Klama }
32113ee8ddeSJakub Wojciech Klama
32213ee8ddeSJakub Wojciech Klama sun.sun_family = AF_UNIX;
32313ee8ddeSJakub Wojciech Klama sun.sun_len = sizeof(struct sockaddr_un);
324ecc28863SEd Schouten strcpy(pathcopy, path);
3258a114a66SEric van Gyzen strlcpy(sun.sun_path, basename(pathcopy), sizeof(sun.sun_path));
326ecc28863SEd Schouten free(pathcopy);
32713ee8ddeSJakub Wojciech Klama
32813ee8ddeSJakub Wojciech Klama if (bindat(fd, s, (struct sockaddr *)&sun, sun.sun_len) < 0) {
32913ee8ddeSJakub Wojciech Klama error = -1;
33013ee8ddeSJakub Wojciech Klama goto out;
33113ee8ddeSJakub Wojciech Klama }
33213ee8ddeSJakub Wojciech Klama
33313ee8ddeSJakub Wojciech Klama if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) {
33413ee8ddeSJakub Wojciech Klama error = -1;
33513ee8ddeSJakub Wojciech Klama goto out;
33613ee8ddeSJakub Wojciech Klama }
33713ee8ddeSJakub Wojciech Klama
33813ee8ddeSJakub Wojciech Klama if (listen(s, 1) < 0) {
33913ee8ddeSJakub Wojciech Klama error = -1;
34013ee8ddeSJakub Wojciech Klama goto out;
34113ee8ddeSJakub Wojciech Klama }
34213ee8ddeSJakub Wojciech Klama
34300ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
34400ef17beSBartek Rutkowski cap_rights_init(&rights, CAP_ACCEPT, CAP_EVENT, CAP_READ, CAP_WRITE);
345abfa3c39SMarcelo Araujo if (caph_rights_limit(s, &rights) == -1)
34600ef17beSBartek Rutkowski errx(EX_OSERR, "Unable to apply rights for sandbox");
34700ef17beSBartek Rutkowski #endif
34813ee8ddeSJakub Wojciech Klama
349621b5090SJohn Baldwin name = get_config_value_node(nvl, "name");
350621b5090SJohn Baldwin if (name == NULL) {
351621b5090SJohn Baldwin EPRINTLN("vtcon: required name missing for port %ld", port);
352621b5090SJohn Baldwin error = -1;
353621b5090SJohn Baldwin goto out;
354621b5090SJohn Baldwin }
355621b5090SJohn Baldwin sock->vss_port = pci_vtcon_port_add(sc, port, name, pci_vtcon_sock_tx, sock);
35613ee8ddeSJakub Wojciech Klama if (sock->vss_port == NULL) {
35713ee8ddeSJakub Wojciech Klama error = -1;
35813ee8ddeSJakub Wojciech Klama goto out;
35913ee8ddeSJakub Wojciech Klama }
36013ee8ddeSJakub Wojciech Klama
36113ee8ddeSJakub Wojciech Klama sock->vss_open = false;
36213ee8ddeSJakub Wojciech Klama sock->vss_conn_fd = -1;
36313ee8ddeSJakub Wojciech Klama sock->vss_server_fd = s;
36413ee8ddeSJakub Wojciech Klama sock->vss_server_evp = mevent_add(s, EVF_READ, pci_vtcon_sock_accept,
36513ee8ddeSJakub Wojciech Klama sock);
36613ee8ddeSJakub Wojciech Klama
36713ee8ddeSJakub Wojciech Klama if (sock->vss_server_evp == NULL) {
36813ee8ddeSJakub Wojciech Klama error = -1;
36913ee8ddeSJakub Wojciech Klama goto out;
37013ee8ddeSJakub Wojciech Klama }
37113ee8ddeSJakub Wojciech Klama
37213ee8ddeSJakub Wojciech Klama out:
37313ee8ddeSJakub Wojciech Klama if (fd != -1)
37413ee8ddeSJakub Wojciech Klama close(fd);
37513ee8ddeSJakub Wojciech Klama
376ba1ca6d2SSean Chittenden if (error != 0) {
377ba1ca6d2SSean Chittenden if (s != -1)
37813ee8ddeSJakub Wojciech Klama close(s);
379ba1ca6d2SSean Chittenden free(sock);
380ba1ca6d2SSean Chittenden }
38113ee8ddeSJakub Wojciech Klama
38213ee8ddeSJakub Wojciech Klama return (error);
38313ee8ddeSJakub Wojciech Klama }
38413ee8ddeSJakub Wojciech Klama
38513ee8ddeSJakub Wojciech Klama static void
pci_vtcon_sock_accept(int fd __unused,enum ev_type t __unused,void * arg)38613ee8ddeSJakub Wojciech Klama pci_vtcon_sock_accept(int fd __unused, enum ev_type t __unused, void *arg)
38713ee8ddeSJakub Wojciech Klama {
38813ee8ddeSJakub Wojciech Klama struct pci_vtcon_sock *sock = (struct pci_vtcon_sock *)arg;
38913ee8ddeSJakub Wojciech Klama int s;
39013ee8ddeSJakub Wojciech Klama
39113ee8ddeSJakub Wojciech Klama s = accept(sock->vss_server_fd, NULL, NULL);
39213ee8ddeSJakub Wojciech Klama if (s < 0)
39313ee8ddeSJakub Wojciech Klama return;
39413ee8ddeSJakub Wojciech Klama
39513ee8ddeSJakub Wojciech Klama if (sock->vss_open) {
39613ee8ddeSJakub Wojciech Klama close(s);
39713ee8ddeSJakub Wojciech Klama return;
39813ee8ddeSJakub Wojciech Klama }
39913ee8ddeSJakub Wojciech Klama
40013ee8ddeSJakub Wojciech Klama sock->vss_open = true;
40113ee8ddeSJakub Wojciech Klama sock->vss_conn_fd = s;
40213ee8ddeSJakub Wojciech Klama sock->vss_conn_evp = mevent_add(s, EVF_READ, pci_vtcon_sock_rx, sock);
403962094d5SJakub Wojciech Klama
40413ee8ddeSJakub Wojciech Klama pci_vtcon_open_port(sock->vss_port, true);
40513ee8ddeSJakub Wojciech Klama }
40613ee8ddeSJakub Wojciech Klama
40713ee8ddeSJakub Wojciech Klama static void
pci_vtcon_sock_rx(int fd __unused,enum ev_type t __unused,void * arg)40813ee8ddeSJakub Wojciech Klama pci_vtcon_sock_rx(int fd __unused, enum ev_type t __unused, void *arg)
40913ee8ddeSJakub Wojciech Klama {
41013ee8ddeSJakub Wojciech Klama struct pci_vtcon_port *port;
41113ee8ddeSJakub Wojciech Klama struct pci_vtcon_sock *sock = (struct pci_vtcon_sock *)arg;
41213ee8ddeSJakub Wojciech Klama struct vqueue_info *vq;
413b0139127SKa Ho Ng struct vi_req req;
41413ee8ddeSJakub Wojciech Klama struct iovec iov;
41513ee8ddeSJakub Wojciech Klama static char dummybuf[2048];
41613ee8ddeSJakub Wojciech Klama int len, n;
41713ee8ddeSJakub Wojciech Klama
41813ee8ddeSJakub Wojciech Klama port = sock->vss_port;
41913ee8ddeSJakub Wojciech Klama vq = pci_vtcon_port_to_vq(port, true);
42013ee8ddeSJakub Wojciech Klama
42113ee8ddeSJakub Wojciech Klama if (!sock->vss_open || !port->vsp_rx_ready) {
42213ee8ddeSJakub Wojciech Klama len = read(sock->vss_conn_fd, dummybuf, sizeof(dummybuf));
42313ee8ddeSJakub Wojciech Klama if (len == 0)
42413ee8ddeSJakub Wojciech Klama goto close;
42513ee8ddeSJakub Wojciech Klama
42613ee8ddeSJakub Wojciech Klama return;
42713ee8ddeSJakub Wojciech Klama }
42813ee8ddeSJakub Wojciech Klama
42913ee8ddeSJakub Wojciech Klama if (!vq_has_descs(vq)) {
43013ee8ddeSJakub Wojciech Klama len = read(sock->vss_conn_fd, dummybuf, sizeof(dummybuf));
43113ee8ddeSJakub Wojciech Klama vq_endchains(vq, 1);
43213ee8ddeSJakub Wojciech Klama if (len == 0)
43313ee8ddeSJakub Wojciech Klama goto close;
43413ee8ddeSJakub Wojciech Klama
43513ee8ddeSJakub Wojciech Klama return;
43613ee8ddeSJakub Wojciech Klama }
43713ee8ddeSJakub Wojciech Klama
43813ee8ddeSJakub Wojciech Klama do {
439b0139127SKa Ho Ng n = vq_getchain(vq, &iov, 1, &req);
44071fbc6faSMark Johnston assert(n == 1);
44113ee8ddeSJakub Wojciech Klama len = readv(sock->vss_conn_fd, &iov, n);
44213ee8ddeSJakub Wojciech Klama
44313ee8ddeSJakub Wojciech Klama if (len == 0 || (len < 0 && errno == EWOULDBLOCK)) {
444d55e0373SVincenzo Maffione vq_retchains(vq, 1);
44513ee8ddeSJakub Wojciech Klama vq_endchains(vq, 0);
44613ee8ddeSJakub Wojciech Klama if (len == 0)
44713ee8ddeSJakub Wojciech Klama goto close;
44813ee8ddeSJakub Wojciech Klama
44913ee8ddeSJakub Wojciech Klama return;
45013ee8ddeSJakub Wojciech Klama }
45113ee8ddeSJakub Wojciech Klama
452b0139127SKa Ho Ng vq_relchain(vq, req.idx, len);
45313ee8ddeSJakub Wojciech Klama } while (vq_has_descs(vq));
45413ee8ddeSJakub Wojciech Klama
45513ee8ddeSJakub Wojciech Klama vq_endchains(vq, 1);
45613ee8ddeSJakub Wojciech Klama
45713ee8ddeSJakub Wojciech Klama close:
45813ee8ddeSJakub Wojciech Klama mevent_delete_close(sock->vss_conn_evp);
45913ee8ddeSJakub Wojciech Klama sock->vss_conn_fd = -1;
46013ee8ddeSJakub Wojciech Klama sock->vss_open = false;
46113ee8ddeSJakub Wojciech Klama }
46213ee8ddeSJakub Wojciech Klama
46313ee8ddeSJakub Wojciech Klama static void
pci_vtcon_sock_tx(struct pci_vtcon_port * port __unused,void * arg __unused,struct iovec * iov,int niov)46498d920d9SMark Johnston pci_vtcon_sock_tx(struct pci_vtcon_port *port __unused, void *arg __unused,
46598d920d9SMark Johnston struct iovec *iov, int niov)
46613ee8ddeSJakub Wojciech Klama {
46713ee8ddeSJakub Wojciech Klama struct pci_vtcon_sock *sock;
468d286418eSJakub Wojciech Klama int i, ret;
46913ee8ddeSJakub Wojciech Klama
47013ee8ddeSJakub Wojciech Klama sock = (struct pci_vtcon_sock *)arg;
47113ee8ddeSJakub Wojciech Klama
47213ee8ddeSJakub Wojciech Klama if (sock->vss_conn_fd == -1)
47313ee8ddeSJakub Wojciech Klama return;
47413ee8ddeSJakub Wojciech Klama
475d286418eSJakub Wojciech Klama for (i = 0; i < niov; i++) {
476d286418eSJakub Wojciech Klama ret = stream_write(sock->vss_conn_fd, iov[i].iov_base,
477d286418eSJakub Wojciech Klama iov[i].iov_len);
478d286418eSJakub Wojciech Klama if (ret <= 0)
479d286418eSJakub Wojciech Klama break;
480d286418eSJakub Wojciech Klama }
48113ee8ddeSJakub Wojciech Klama
482d286418eSJakub Wojciech Klama if (ret <= 0) {
48313ee8ddeSJakub Wojciech Klama mevent_delete_close(sock->vss_conn_evp);
48413ee8ddeSJakub Wojciech Klama sock->vss_conn_fd = -1;
48513ee8ddeSJakub Wojciech Klama sock->vss_open = false;
48613ee8ddeSJakub Wojciech Klama }
48713ee8ddeSJakub Wojciech Klama }
48813ee8ddeSJakub Wojciech Klama
48913ee8ddeSJakub Wojciech Klama static void
pci_vtcon_control_tx(struct pci_vtcon_port * port,void * arg __unused,struct iovec * iov,int niov)49098d920d9SMark Johnston pci_vtcon_control_tx(struct pci_vtcon_port *port, void *arg __unused,
49198d920d9SMark Johnston struct iovec *iov, int niov)
49213ee8ddeSJakub Wojciech Klama {
49313ee8ddeSJakub Wojciech Klama struct pci_vtcon_softc *sc;
49413ee8ddeSJakub Wojciech Klama struct pci_vtcon_port *tmp;
49513ee8ddeSJakub Wojciech Klama struct pci_vtcon_control resp, *ctrl;
49613ee8ddeSJakub Wojciech Klama int i;
49713ee8ddeSJakub Wojciech Klama
49813ee8ddeSJakub Wojciech Klama assert(niov == 1);
49913ee8ddeSJakub Wojciech Klama
50013ee8ddeSJakub Wojciech Klama sc = port->vsp_sc;
50113ee8ddeSJakub Wojciech Klama ctrl = (struct pci_vtcon_control *)iov->iov_base;
50213ee8ddeSJakub Wojciech Klama
50313ee8ddeSJakub Wojciech Klama switch (ctrl->event) {
50413ee8ddeSJakub Wojciech Klama case VTCON_DEVICE_READY:
505962094d5SJakub Wojciech Klama sc->vsc_ready = true;
50613ee8ddeSJakub Wojciech Klama /* set port ready events for registered ports */
50713ee8ddeSJakub Wojciech Klama for (i = 0; i < VTCON_MAXPORTS; i++) {
50813ee8ddeSJakub Wojciech Klama tmp = &sc->vsc_ports[i];
50913ee8ddeSJakub Wojciech Klama if (tmp->vsp_enabled)
51013ee8ddeSJakub Wojciech Klama pci_vtcon_announce_port(tmp);
511962094d5SJakub Wojciech Klama
512962094d5SJakub Wojciech Klama if (tmp->vsp_open)
513962094d5SJakub Wojciech Klama pci_vtcon_open_port(tmp, true);
51413ee8ddeSJakub Wojciech Klama }
51513ee8ddeSJakub Wojciech Klama break;
51613ee8ddeSJakub Wojciech Klama
51713ee8ddeSJakub Wojciech Klama case VTCON_PORT_READY:
518621b5090SJohn Baldwin tmp = &sc->vsc_ports[ctrl->id];
519621b5090SJohn Baldwin if (ctrl->id >= VTCON_MAXPORTS || !tmp->vsp_enabled) {
520332eff95SVincenzo Maffione WPRINTF(("VTCON_PORT_READY event for unknown port %d",
52113ee8ddeSJakub Wojciech Klama ctrl->id));
52213ee8ddeSJakub Wojciech Klama return;
52313ee8ddeSJakub Wojciech Klama }
52413ee8ddeSJakub Wojciech Klama
52513ee8ddeSJakub Wojciech Klama if (tmp->vsp_console) {
52613ee8ddeSJakub Wojciech Klama resp.event = VTCON_CONSOLE_PORT;
52713ee8ddeSJakub Wojciech Klama resp.id = ctrl->id;
52813ee8ddeSJakub Wojciech Klama resp.value = 1;
52913ee8ddeSJakub Wojciech Klama pci_vtcon_control_send(sc, &resp, NULL, 0);
53013ee8ddeSJakub Wojciech Klama }
53113ee8ddeSJakub Wojciech Klama break;
53213ee8ddeSJakub Wojciech Klama }
53313ee8ddeSJakub Wojciech Klama }
53413ee8ddeSJakub Wojciech Klama
53513ee8ddeSJakub Wojciech Klama static void
pci_vtcon_announce_port(struct pci_vtcon_port * port)53613ee8ddeSJakub Wojciech Klama pci_vtcon_announce_port(struct pci_vtcon_port *port)
53713ee8ddeSJakub Wojciech Klama {
53813ee8ddeSJakub Wojciech Klama struct pci_vtcon_control event;
53913ee8ddeSJakub Wojciech Klama
54013ee8ddeSJakub Wojciech Klama event.id = port->vsp_id;
54113ee8ddeSJakub Wojciech Klama event.event = VTCON_DEVICE_ADD;
54213ee8ddeSJakub Wojciech Klama event.value = 1;
54313ee8ddeSJakub Wojciech Klama pci_vtcon_control_send(port->vsp_sc, &event, NULL, 0);
54413ee8ddeSJakub Wojciech Klama
54513ee8ddeSJakub Wojciech Klama event.event = VTCON_PORT_NAME;
54613ee8ddeSJakub Wojciech Klama pci_vtcon_control_send(port->vsp_sc, &event, port->vsp_name,
54713ee8ddeSJakub Wojciech Klama strlen(port->vsp_name));
54813ee8ddeSJakub Wojciech Klama }
54913ee8ddeSJakub Wojciech Klama
55013ee8ddeSJakub Wojciech Klama static void
pci_vtcon_open_port(struct pci_vtcon_port * port,bool open)55113ee8ddeSJakub Wojciech Klama pci_vtcon_open_port(struct pci_vtcon_port *port, bool open)
55213ee8ddeSJakub Wojciech Klama {
55313ee8ddeSJakub Wojciech Klama struct pci_vtcon_control event;
55413ee8ddeSJakub Wojciech Klama
555962094d5SJakub Wojciech Klama if (!port->vsp_sc->vsc_ready) {
556962094d5SJakub Wojciech Klama port->vsp_open = true;
557962094d5SJakub Wojciech Klama return;
558962094d5SJakub Wojciech Klama }
559962094d5SJakub Wojciech Klama
56013ee8ddeSJakub Wojciech Klama event.id = port->vsp_id;
56113ee8ddeSJakub Wojciech Klama event.event = VTCON_PORT_OPEN;
56213ee8ddeSJakub Wojciech Klama event.value = (int)open;
56313ee8ddeSJakub Wojciech Klama pci_vtcon_control_send(port->vsp_sc, &event, NULL, 0);
56413ee8ddeSJakub Wojciech Klama }
56513ee8ddeSJakub Wojciech Klama
56613ee8ddeSJakub Wojciech Klama static void
pci_vtcon_control_send(struct pci_vtcon_softc * sc,struct pci_vtcon_control * ctrl,const void * payload,size_t len)56713ee8ddeSJakub Wojciech Klama pci_vtcon_control_send(struct pci_vtcon_softc *sc,
56813ee8ddeSJakub Wojciech Klama struct pci_vtcon_control *ctrl, const void *payload, size_t len)
56913ee8ddeSJakub Wojciech Klama {
57013ee8ddeSJakub Wojciech Klama struct vqueue_info *vq;
571b0139127SKa Ho Ng struct vi_req req;
57213ee8ddeSJakub Wojciech Klama struct iovec iov;
57313ee8ddeSJakub Wojciech Klama int n;
57413ee8ddeSJakub Wojciech Klama
575*b34a4edeSPierre Pronchery if (len > SIZE_T_MAX - sizeof(struct pci_vtcon_control))
576*b34a4edeSPierre Pronchery return;
577*b34a4edeSPierre Pronchery
57813ee8ddeSJakub Wojciech Klama vq = pci_vtcon_port_to_vq(&sc->vsc_control_port, true);
57913ee8ddeSJakub Wojciech Klama
58013ee8ddeSJakub Wojciech Klama if (!vq_has_descs(vq))
58113ee8ddeSJakub Wojciech Klama return;
58213ee8ddeSJakub Wojciech Klama
583b0139127SKa Ho Ng n = vq_getchain(vq, &iov, 1, &req);
58413ee8ddeSJakub Wojciech Klama assert(n == 1);
58513ee8ddeSJakub Wojciech Klama
586*b34a4edeSPierre Pronchery if (iov.iov_len < sizeof(struct pci_vtcon_control) + len)
58789340029SPierre Pronchery goto out;
58889340029SPierre Pronchery
58913ee8ddeSJakub Wojciech Klama memcpy(iov.iov_base, ctrl, sizeof(struct pci_vtcon_control));
590*b34a4edeSPierre Pronchery if (len > 0)
59163898728SMark Johnston memcpy((uint8_t *)iov.iov_base +
59263898728SMark Johnston sizeof(struct pci_vtcon_control), payload, len);
59313ee8ddeSJakub Wojciech Klama
59489340029SPierre Pronchery out:
595b0139127SKa Ho Ng vq_relchain(vq, req.idx, sizeof(struct pci_vtcon_control) + len);
59613ee8ddeSJakub Wojciech Klama vq_endchains(vq, 1);
59713ee8ddeSJakub Wojciech Klama }
59813ee8ddeSJakub Wojciech Klama
59913ee8ddeSJakub Wojciech Klama
60013ee8ddeSJakub Wojciech Klama static void
pci_vtcon_notify_tx(void * vsc,struct vqueue_info * vq)60113ee8ddeSJakub Wojciech Klama pci_vtcon_notify_tx(void *vsc, struct vqueue_info *vq)
60213ee8ddeSJakub Wojciech Klama {
60313ee8ddeSJakub Wojciech Klama struct pci_vtcon_softc *sc;
60413ee8ddeSJakub Wojciech Klama struct pci_vtcon_port *port;
60513ee8ddeSJakub Wojciech Klama struct iovec iov[1];
606b0139127SKa Ho Ng struct vi_req req;
60771fbc6faSMark Johnston int n;
60813ee8ddeSJakub Wojciech Klama
60913ee8ddeSJakub Wojciech Klama sc = vsc;
61013ee8ddeSJakub Wojciech Klama port = pci_vtcon_vq_to_port(sc, vq);
61113ee8ddeSJakub Wojciech Klama
61213ee8ddeSJakub Wojciech Klama while (vq_has_descs(vq)) {
613b0139127SKa Ho Ng n = vq_getchain(vq, iov, 1, &req);
61471fbc6faSMark Johnston assert(n == 1);
61513ee8ddeSJakub Wojciech Klama if (port != NULL)
61613ee8ddeSJakub Wojciech Klama port->vsp_cb(port, port->vsp_arg, iov, 1);
61713ee8ddeSJakub Wojciech Klama
61813ee8ddeSJakub Wojciech Klama /*
61913ee8ddeSJakub Wojciech Klama * Release this chain and handle more
62013ee8ddeSJakub Wojciech Klama */
621b0139127SKa Ho Ng vq_relchain(vq, req.idx, 0);
62213ee8ddeSJakub Wojciech Klama }
62313ee8ddeSJakub Wojciech Klama vq_endchains(vq, 1); /* Generate interrupt if appropriate. */
62413ee8ddeSJakub Wojciech Klama }
62513ee8ddeSJakub Wojciech Klama
62613ee8ddeSJakub Wojciech Klama static void
pci_vtcon_notify_rx(void * vsc,struct vqueue_info * vq)62713ee8ddeSJakub Wojciech Klama pci_vtcon_notify_rx(void *vsc, struct vqueue_info *vq)
62813ee8ddeSJakub Wojciech Klama {
62913ee8ddeSJakub Wojciech Klama struct pci_vtcon_softc *sc;
63013ee8ddeSJakub Wojciech Klama struct pci_vtcon_port *port;
63113ee8ddeSJakub Wojciech Klama
63213ee8ddeSJakub Wojciech Klama sc = vsc;
63313ee8ddeSJakub Wojciech Klama port = pci_vtcon_vq_to_port(sc, vq);
63413ee8ddeSJakub Wojciech Klama
63513ee8ddeSJakub Wojciech Klama if (!port->vsp_rx_ready) {
63613ee8ddeSJakub Wojciech Klama port->vsp_rx_ready = 1;
63717e9052cSVincenzo Maffione vq_kick_disable(vq);
63813ee8ddeSJakub Wojciech Klama }
63913ee8ddeSJakub Wojciech Klama }
64013ee8ddeSJakub Wojciech Klama
641621b5090SJohn Baldwin /*
642621b5090SJohn Baldwin * Each console device has a "port" node which contains nodes for
643621b5090SJohn Baldwin * each port. Ports are numbered starting at 0.
644621b5090SJohn Baldwin */
64513ee8ddeSJakub Wojciech Klama static int
pci_vtcon_legacy_config_port(nvlist_t * nvl,int port,char * opt)646621b5090SJohn Baldwin pci_vtcon_legacy_config_port(nvlist_t *nvl, int port, char *opt)
647621b5090SJohn Baldwin {
648621b5090SJohn Baldwin char *name, *path;
649621b5090SJohn Baldwin char node_name[sizeof("XX")];
650621b5090SJohn Baldwin nvlist_t *port_nvl;
651621b5090SJohn Baldwin
652621b5090SJohn Baldwin name = strsep(&opt, "=");
653621b5090SJohn Baldwin path = opt;
654621b5090SJohn Baldwin if (path == NULL) {
655621b5090SJohn Baldwin EPRINTLN("vtcon: port %s requires a path", name);
656621b5090SJohn Baldwin return (-1);
657621b5090SJohn Baldwin }
658621b5090SJohn Baldwin if (port >= VTCON_MAXPORTS) {
659621b5090SJohn Baldwin EPRINTLN("vtcon: too many ports");
660621b5090SJohn Baldwin return (-1);
661621b5090SJohn Baldwin }
662621b5090SJohn Baldwin snprintf(node_name, sizeof(node_name), "%d", port);
663621b5090SJohn Baldwin port_nvl = create_relative_config_node(nvl, node_name);
664621b5090SJohn Baldwin set_config_value_node(port_nvl, "name", name);
665621b5090SJohn Baldwin set_config_value_node(port_nvl, "path", path);
666621b5090SJohn Baldwin return (0);
667621b5090SJohn Baldwin }
668621b5090SJohn Baldwin
669621b5090SJohn Baldwin static int
pci_vtcon_legacy_config(nvlist_t * nvl,const char * opts)670621b5090SJohn Baldwin pci_vtcon_legacy_config(nvlist_t *nvl, const char *opts)
671621b5090SJohn Baldwin {
672621b5090SJohn Baldwin char *opt, *str, *tofree;
673621b5090SJohn Baldwin nvlist_t *ports_nvl;
674621b5090SJohn Baldwin int error, port;
675621b5090SJohn Baldwin
676621b5090SJohn Baldwin ports_nvl = create_relative_config_node(nvl, "port");
677621b5090SJohn Baldwin tofree = str = strdup(opts);
678621b5090SJohn Baldwin error = 0;
679621b5090SJohn Baldwin port = 0;
680621b5090SJohn Baldwin while ((opt = strsep(&str, ",")) != NULL) {
681621b5090SJohn Baldwin error = pci_vtcon_legacy_config_port(ports_nvl, port, opt);
682621b5090SJohn Baldwin if (error)
683621b5090SJohn Baldwin break;
684621b5090SJohn Baldwin port++;
685621b5090SJohn Baldwin }
686621b5090SJohn Baldwin free(tofree);
687621b5090SJohn Baldwin return (error);
688621b5090SJohn Baldwin }
689621b5090SJohn Baldwin
690621b5090SJohn Baldwin static int
pci_vtcon_init(struct pci_devinst * pi,nvlist_t * nvl)6916a284cacSJohn Baldwin pci_vtcon_init(struct pci_devinst *pi, nvlist_t *nvl)
69213ee8ddeSJakub Wojciech Klama {
69313ee8ddeSJakub Wojciech Klama struct pci_vtcon_softc *sc;
694621b5090SJohn Baldwin nvlist_t *ports_nvl;
69513ee8ddeSJakub Wojciech Klama int i;
69613ee8ddeSJakub Wojciech Klama
69713ee8ddeSJakub Wojciech Klama sc = calloc(1, sizeof(struct pci_vtcon_softc));
69813ee8ddeSJakub Wojciech Klama sc->vsc_config = calloc(1, sizeof(struct pci_vtcon_config));
69913ee8ddeSJakub Wojciech Klama sc->vsc_config->max_nr_ports = VTCON_MAXPORTS;
70013ee8ddeSJakub Wojciech Klama sc->vsc_config->cols = 80;
70113ee8ddeSJakub Wojciech Klama sc->vsc_config->rows = 25;
70213ee8ddeSJakub Wojciech Klama
703f6f357efSAndy Fiddaman pthread_mutex_init(&sc->vsc_mtx, NULL);
704f6f357efSAndy Fiddaman
70513ee8ddeSJakub Wojciech Klama vi_softc_linkup(&sc->vsc_vs, &vtcon_vi_consts, sc, pi, sc->vsc_queues);
70613ee8ddeSJakub Wojciech Klama sc->vsc_vs.vs_mtx = &sc->vsc_mtx;
70713ee8ddeSJakub Wojciech Klama
70813ee8ddeSJakub Wojciech Klama for (i = 0; i < VTCON_MAXQ; i++) {
70913ee8ddeSJakub Wojciech Klama sc->vsc_queues[i].vq_qsize = VTCON_RINGSZ;
71013ee8ddeSJakub Wojciech Klama sc->vsc_queues[i].vq_notify = i % 2 == 0
71113ee8ddeSJakub Wojciech Klama ? pci_vtcon_notify_rx
71213ee8ddeSJakub Wojciech Klama : pci_vtcon_notify_tx;
71313ee8ddeSJakub Wojciech Klama }
71413ee8ddeSJakub Wojciech Klama
71513ee8ddeSJakub Wojciech Klama /* initialize config space */
71613ee8ddeSJakub Wojciech Klama pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_CONSOLE);
71713ee8ddeSJakub Wojciech Klama pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);
71813ee8ddeSJakub Wojciech Klama pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_SIMPLECOMM);
71954ac6f72SKa Ho Ng pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_CONSOLE);
72013ee8ddeSJakub Wojciech Klama pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR);
72113ee8ddeSJakub Wojciech Klama
72213ee8ddeSJakub Wojciech Klama if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix()))
72313ee8ddeSJakub Wojciech Klama return (1);
72413ee8ddeSJakub Wojciech Klama vi_set_io_bar(&sc->vsc_vs, 0);
72513ee8ddeSJakub Wojciech Klama
72613ee8ddeSJakub Wojciech Klama /* create control port */
72713ee8ddeSJakub Wojciech Klama sc->vsc_control_port.vsp_sc = sc;
72813ee8ddeSJakub Wojciech Klama sc->vsc_control_port.vsp_txq = 2;
72913ee8ddeSJakub Wojciech Klama sc->vsc_control_port.vsp_rxq = 3;
73013ee8ddeSJakub Wojciech Klama sc->vsc_control_port.vsp_cb = pci_vtcon_control_tx;
73113ee8ddeSJakub Wojciech Klama sc->vsc_control_port.vsp_enabled = true;
73213ee8ddeSJakub Wojciech Klama
733621b5090SJohn Baldwin ports_nvl = find_relative_config_node(nvl, "port");
734621b5090SJohn Baldwin if (ports_nvl != NULL) {
735621b5090SJohn Baldwin const char *name;
736621b5090SJohn Baldwin void *cookie;
737621b5090SJohn Baldwin int type;
73813ee8ddeSJakub Wojciech Klama
739621b5090SJohn Baldwin cookie = NULL;
740621b5090SJohn Baldwin while ((name = nvlist_next(ports_nvl, &type, &cookie)) !=
741621b5090SJohn Baldwin NULL) {
742621b5090SJohn Baldwin if (type != NV_TYPE_NVLIST)
743621b5090SJohn Baldwin continue;
744621b5090SJohn Baldwin
745621b5090SJohn Baldwin if (pci_vtcon_sock_add(sc, name,
746621b5090SJohn Baldwin nvlist_get_nvlist(ports_nvl, name)) < 0) {
747332eff95SVincenzo Maffione EPRINTLN("cannot create port %s: %s",
748621b5090SJohn Baldwin name, strerror(errno));
74913ee8ddeSJakub Wojciech Klama return (1);
75013ee8ddeSJakub Wojciech Klama }
75113ee8ddeSJakub Wojciech Klama }
752621b5090SJohn Baldwin }
75313ee8ddeSJakub Wojciech Klama
75413ee8ddeSJakub Wojciech Klama return (0);
75513ee8ddeSJakub Wojciech Klama }
75613ee8ddeSJakub Wojciech Klama
75737045dfaSMark Johnston static const struct pci_devemu pci_de_vcon = {
75813ee8ddeSJakub Wojciech Klama .pe_emu = "virtio-console",
75913ee8ddeSJakub Wojciech Klama .pe_init = pci_vtcon_init,
76013ee8ddeSJakub Wojciech Klama .pe_barwrite = vi_pci_write,
7613cdfaefaSYan Ka Chiu .pe_barread = vi_pci_read,
7623cdfaefaSYan Ka Chiu .pe_legacy_config = pci_vtcon_legacy_config,
76313ee8ddeSJakub Wojciech Klama };
76413ee8ddeSJakub Wojciech Klama PCI_EMUL_SET(pci_de_vcon);
765