2 * Vhost-user vsock virtio device
4 * Copyright 2020 Red Hat, Inc.
6 * This work is licensed under the terms of the GNU GPL, version 2 or
7 * (at your option) any later version. See the COPYING file in the
11 #include "qemu/osdep.h"
13 #include "qapi/error.h"
14 #include "qemu/error-report.h"
15 #include "hw/qdev-properties.h"
16 #include "hw/virtio/vhost-user-vsock.h"
18 static const int user_feature_bits
[] = {
20 VIRTIO_RING_F_INDIRECT_DESC
,
21 VIRTIO_RING_F_EVENT_IDX
,
22 VIRTIO_F_NOTIFY_ON_EMPTY
,
23 VHOST_INVALID_FEATURE_BIT
26 static void vuv_get_config(VirtIODevice
*vdev
, uint8_t *config
)
28 VHostUserVSock
*vsock
= VHOST_USER_VSOCK(vdev
);
30 memcpy(config
, &vsock
->vsockcfg
, sizeof(struct virtio_vsock_config
));
33 static int vuv_handle_config_change(struct vhost_dev
*dev
)
35 VHostUserVSock
*vsock
= VHOST_USER_VSOCK(dev
->vdev
);
36 int ret
= vhost_dev_get_config(dev
, (uint8_t *)&vsock
->vsockcfg
,
37 sizeof(struct virtio_vsock_config
));
39 error_report("get config space failed");
43 virtio_notify_config(dev
->vdev
);
48 const VhostDevConfigOps vsock_ops
= {
49 .vhost_dev_config_notifier
= vuv_handle_config_change
,
52 static void vuv_set_status(VirtIODevice
*vdev
, uint8_t status
)
54 VHostVSockCommon
*vvc
= VHOST_VSOCK_COMMON(vdev
);
55 bool should_start
= status
& VIRTIO_CONFIG_S_DRIVER_OK
;
57 if (!vdev
->vm_running
) {
61 if (vvc
->vhost_dev
.started
== should_start
) {
66 int ret
= vhost_vsock_common_start(vdev
);
71 vhost_vsock_common_stop(vdev
);
75 static uint64_t vuv_get_features(VirtIODevice
*vdev
,
79 VHostVSockCommon
*vvc
= VHOST_VSOCK_COMMON(vdev
);
81 return vhost_get_features(&vvc
->vhost_dev
, user_feature_bits
, features
);
84 static const VMStateDescription vuv_vmstate
= {
85 .name
= "vhost-user-vsock",
89 static void vuv_device_realize(DeviceState
*dev
, Error
**errp
)
91 VHostVSockCommon
*vvc
= VHOST_VSOCK_COMMON(dev
);
92 VirtIODevice
*vdev
= VIRTIO_DEVICE(dev
);
93 VHostUserVSock
*vsock
= VHOST_USER_VSOCK(dev
);
96 if (!vsock
->conf
.chardev
.chr
) {
97 error_setg(errp
, "missing chardev");
101 if (!vhost_user_init(&vsock
->vhost_user
, &vsock
->conf
.chardev
, errp
)) {
105 vhost_vsock_common_realize(vdev
, "vhost-user-vsock");
107 vhost_dev_set_config_notifier(&vvc
->vhost_dev
, &vsock_ops
);
109 ret
= vhost_dev_init(&vvc
->vhost_dev
, &vsock
->vhost_user
,
110 VHOST_BACKEND_TYPE_USER
, 0);
112 error_setg_errno(errp
, -ret
, "vhost_dev_init failed");
116 ret
= vhost_dev_get_config(&vvc
->vhost_dev
, (uint8_t *)&vsock
->vsockcfg
,
117 sizeof(struct virtio_vsock_config
));
119 error_setg_errno(errp
, -ret
, "get config space failed");
126 vhost_dev_cleanup(&vvc
->vhost_dev
);
128 vhost_vsock_common_unrealize(vdev
);
129 vhost_user_cleanup(&vsock
->vhost_user
);
133 static void vuv_device_unrealize(DeviceState
*dev
)
135 VHostVSockCommon
*vvc
= VHOST_VSOCK_COMMON(dev
);
136 VirtIODevice
*vdev
= VIRTIO_DEVICE(dev
);
137 VHostUserVSock
*vsock
= VHOST_USER_VSOCK(dev
);
139 /* This will stop vhost backend if appropriate. */
140 vuv_set_status(vdev
, 0);
142 vhost_dev_cleanup(&vvc
->vhost_dev
);
144 vhost_vsock_common_unrealize(vdev
);
146 vhost_user_cleanup(&vsock
->vhost_user
);
150 static Property vuv_properties
[] = {
151 DEFINE_PROP_CHR("chardev", VHostUserVSock
, conf
.chardev
),
152 DEFINE_PROP_END_OF_LIST(),
155 static void vuv_class_init(ObjectClass
*klass
, void *data
)
157 DeviceClass
*dc
= DEVICE_CLASS(klass
);
158 VirtioDeviceClass
*vdc
= VIRTIO_DEVICE_CLASS(klass
);
160 device_class_set_props(dc
, vuv_properties
);
161 dc
->vmsd
= &vuv_vmstate
;
162 vdc
->realize
= vuv_device_realize
;
163 vdc
->unrealize
= vuv_device_unrealize
;
164 vdc
->get_features
= vuv_get_features
;
165 vdc
->get_config
= vuv_get_config
;
166 vdc
->set_status
= vuv_set_status
;
169 static const TypeInfo vuv_info
= {
170 .name
= TYPE_VHOST_USER_VSOCK
,
171 .parent
= TYPE_VHOST_VSOCK_COMMON
,
172 .instance_size
= sizeof(VHostUserVSock
),
173 .class_init
= vuv_class_init
,
176 static void vuv_register_types(void)
178 type_register_static(&vuv_info
);
181 type_init(vuv_register_types
)