aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/um/drivers/Kconfig7
-rw-r--r--arch/um/drivers/Makefile1
-rw-r--r--arch/um/drivers/vhost_user.h102
-rw-r--r--arch/um/drivers/virtio_uml.c1002
-rw-r--r--arch/um/include/asm/irq.h5
-rw-r--r--arch/um/include/shared/os.h5
-rw-r--r--arch/um/kernel/ksyms.c2
-rw-r--r--arch/um/kernel/mem.c1
-rw-r--r--arch/um/kernel/physmem.c1
-rw-r--r--arch/um/kernel/um_arch.c1
-rw-r--r--arch/um/os-Linux/file.c44
11 files changed, 1169 insertions, 2 deletions
diff --git a/arch/um/drivers/Kconfig b/arch/um/drivers/Kconfig
index 2638e46f50cc..fea5a0d522dc 100644
--- a/arch/um/drivers/Kconfig
+++ b/arch/um/drivers/Kconfig
@@ -335,3 +335,10 @@ config UML_NET_SLIRP
335 Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp" 335 Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp"
336 336
337endmenu 337endmenu
338
339config VIRTIO_UML
340 tristate "UML driver for virtio devices"
341 select VIRTIO
342 help
343 This driver provides support for virtio based paravirtual device
344 drivers over vhost-user sockets.
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
index 693319839f69..3edf0a7cfd25 100644
--- a/arch/um/drivers/Makefile
+++ b/arch/um/drivers/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o
61obj-$(CONFIG_UML_WATCHDOG) += harddog.o 61obj-$(CONFIG_UML_WATCHDOG) += harddog.o
62obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o 62obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o
63obj-$(CONFIG_UML_RANDOM) += random.o 63obj-$(CONFIG_UML_RANDOM) += random.o
64obj-$(CONFIG_VIRTIO_UML) += virtio_uml.o
64 65
65# pcap_user.o must be added explicitly. 66# pcap_user.o must be added explicitly.
66USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o vde_user.o vector_user.o 67USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o vde_user.o vector_user.o
diff --git a/arch/um/drivers/vhost_user.h b/arch/um/drivers/vhost_user.h
new file mode 100644
index 000000000000..2a9829b0782b
--- /dev/null
+++ b/arch/um/drivers/vhost_user.h
@@ -0,0 +1,102 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/* Vhost-user protocol */
3
4#ifndef __VHOST_USER_H__
5#define __VHOST_USER_H__
6
7/* Message flags */
8#define VHOST_USER_FLAG_REPLY BIT(2)
9/* Feature bits */
10#define VHOST_USER_F_PROTOCOL_FEATURES 30
11/* Protocol feature bits */
12#define VHOST_USER_PROTOCOL_F_CONFIG 9
13/* Vring state index masks */
14#define VHOST_USER_VRING_INDEX_MASK 0xff
15#define VHOST_USER_VRING_POLL_MASK BIT(8)
16
17/* Supported version */
18#define VHOST_USER_VERSION 1
19/* Supported transport features */
20#define VHOST_USER_SUPPORTED_F BIT_ULL(VHOST_USER_F_PROTOCOL_FEATURES)
21/* Supported protocol features */
22#define VHOST_USER_SUPPORTED_PROTOCOL_F BIT_ULL(VHOST_USER_PROTOCOL_F_CONFIG)
23
24enum vhost_user_request {
25 VHOST_USER_GET_FEATURES = 1,
26 VHOST_USER_SET_FEATURES = 2,
27 VHOST_USER_SET_OWNER = 3,
28 VHOST_USER_RESET_OWNER = 4,
29 VHOST_USER_SET_MEM_TABLE = 5,
30 VHOST_USER_SET_LOG_BASE = 6,
31 VHOST_USER_SET_LOG_FD = 7,
32 VHOST_USER_SET_VRING_NUM = 8,
33 VHOST_USER_SET_VRING_ADDR = 9,
34 VHOST_USER_SET_VRING_BASE = 10,
35 VHOST_USER_GET_VRING_BASE = 11,
36 VHOST_USER_SET_VRING_KICK = 12,
37 VHOST_USER_SET_VRING_CALL = 13,
38 VHOST_USER_SET_VRING_ERR = 14,
39 VHOST_USER_GET_PROTOCOL_FEATURES = 15,
40 VHOST_USER_SET_PROTOCOL_FEATURES = 16,
41 VHOST_USER_GET_QUEUE_NUM = 17,
42 VHOST_USER_SET_VRING_ENABLE = 18,
43 VHOST_USER_SEND_RARP = 19,
44 VHOST_USER_NET_SEND_MTU = 20,
45 VHOST_USER_SET_SLAVE_REQ_FD = 21,
46 VHOST_USER_IOTLB_MSG = 22,
47 VHOST_USER_SET_VRING_ENDIAN = 23,
48 VHOST_USER_GET_CONFIG = 24,
49 VHOST_USER_SET_CONFIG = 25,
50};
51
52struct vhost_user_header {
53 u32 request; /* Use enum vhost_user_request */
54 u32 flags;
55 u32 size;
56} __packed;
57
58struct vhost_user_config {
59 u32 offset;
60 u32 size;
61 u32 flags;
62 u8 payload[0]; /* Variable length */
63} __packed;
64
65struct vhost_user_vring_state {
66 u32 index;
67 u32 num;
68} __packed;
69
70struct vhost_user_vring_addr {
71 u32 index;
72 u32 flags;
73 u64 desc, used, avail, log;
74} __packed;
75
76struct vhost_user_mem_region {
77 u64 guest_addr;
78 u64 size;
79 u64 user_addr;
80 u64 mmap_offset;
81} __packed;
82
83struct vhost_user_mem_regions {
84 u32 num;
85 u32 padding;
86 struct vhost_user_mem_region regions[2]; /* Currently supporting 2 */
87} __packed;
88
89union vhost_user_payload {
90 u64 integer;
91 struct vhost_user_config config;
92 struct vhost_user_vring_state vring_state;
93 struct vhost_user_vring_addr vring_addr;
94 struct vhost_user_mem_regions mem_regions;
95};
96
97struct vhost_user_msg {
98 struct vhost_user_header header;
99 union vhost_user_payload payload;
100} __packed;
101
102#endif
diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c
new file mode 100644
index 000000000000..a63da4fcc5ae
--- /dev/null
+++ b/arch/um/drivers/virtio_uml.c
@@ -0,0 +1,1002 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Virtio vhost-user driver
4 *
5 * Copyright(c) 2019 Intel Corporation
6 *
7 * This module allows virtio devices to be used over a vhost-user socket.
8 *
9 * Guest devices can be instantiated by kernel module or command line
10 * parameters. One device will be created for each parameter. Syntax:
11 *
12 * [virtio_uml.]device=<socket>:<virtio_id>[:<platform_id>]
13 * where:
14 * <socket> := vhost-user socket path to connect
15 * <virtio_id> := virtio device id (as in virtio_ids.h)
16 * <platform_id> := (optional) platform device id
17 *
18 * example:
19 * virtio_uml.device=/var/uml.socket:1
20 *
21 * Based on Virtio MMIO driver by Pawel Moll, copyright 2011-2014, ARM Ltd.
22 */
23#include <linux/module.h>
24#include <linux/platform_device.h>
25#include <linux/slab.h>
26#include <linux/virtio.h>
27#include <linux/virtio_config.h>
28#include <linux/virtio_ring.h>
29#include <shared/as-layout.h>
30#include <irq_kern.h>
31#include <init.h>
32#include <os.h>
33#include "vhost_user.h"
34
35/* Workaround due to a conflict between irq_user.h and irqreturn.h */
36#ifdef IRQ_NONE
37#undef IRQ_NONE
38#endif
39
40#define MAX_SUPPORTED_QUEUE_SIZE 256
41
42#define to_virtio_uml_device(_vdev) \
43 container_of(_vdev, struct virtio_uml_device, vdev)
44
45struct virtio_uml_device {
46 struct virtio_device vdev;
47 struct platform_device *pdev;
48
49 int sock;
50 u64 features;
51 u64 protocol_features;
52 u8 status;
53};
54
55struct virtio_uml_vq_info {
56 int kick_fd, call_fd;
57 char name[32];
58};
59
60extern unsigned long long physmem_size, highmem;
61
62#define vu_err(vu_dev, ...) dev_err(&(vu_dev)->pdev->dev, __VA_ARGS__)
63
64/* Vhost-user protocol */
65
66static int full_sendmsg_fds(int fd, const void *buf, unsigned int len,
67 const int *fds, unsigned int fds_num)
68{
69 int rc;
70
71 do {
72 rc = os_sendmsg_fds(fd, buf, len, fds, fds_num);
73 if (rc > 0) {
74 buf += rc;
75 len -= rc;
76 fds = NULL;
77 fds_num = 0;
78 }
79 } while (len && (rc >= 0 || rc == -EINTR));
80
81 if (rc < 0)
82 return rc;
83 return 0;
84}
85
86static int full_read(int fd, void *buf, int len)
87{
88 int rc;
89
90 do {
91 rc = os_read_file(fd, buf, len);
92 if (rc > 0) {
93 buf += rc;
94 len -= rc;
95 }
96 } while (len && (rc > 0 || rc == -EINTR));
97
98 if (rc < 0)
99 return rc;
100 if (rc == 0)
101 return -ECONNRESET;
102 return 0;
103}
104
105static int vhost_user_recv_header(struct virtio_uml_device *vu_dev,
106 struct vhost_user_msg *msg)
107{
108 size_t size = sizeof(msg->header);
109 int rc;
110
111 rc = full_read(vu_dev->sock, (void *) msg, size);
112 if (rc)
113 return rc;
114 if (msg->header.flags != (VHOST_USER_FLAG_REPLY | VHOST_USER_VERSION))
115 return -EPROTO;
116 return 0;
117}
118
119static int vhost_user_recv(struct virtio_uml_device *vu_dev,
120 struct vhost_user_msg *msg,
121 size_t max_payload_size)
122{
123 size_t size;
124 int rc = vhost_user_recv_header(vu_dev, msg);
125
126 if (rc)
127 return rc;
128 size = msg->header.size;
129 if (size > max_payload_size)
130 return -EPROTO;
131 return full_read(vu_dev->sock, (void *) &msg->payload, size);
132}
133
134static int vhost_user_recv_u64(struct virtio_uml_device *vu_dev,
135 u64 *value)
136{
137 struct vhost_user_msg msg;
138 int rc = vhost_user_recv(vu_dev, &msg, sizeof(msg.payload.integer));
139
140 if (rc)
141 return rc;
142 if (msg.header.size != sizeof(msg.payload.integer))
143 return -EPROTO;
144 *value = msg.payload.integer;
145 return 0;
146}
147
148static int vhost_user_send(struct virtio_uml_device *vu_dev,
149 struct vhost_user_msg *msg,
150 int *fds, size_t num_fds)
151{
152 size_t size = sizeof(msg->header) + msg->header.size;
153
154 msg->header.flags |= VHOST_USER_VERSION;
155 return full_sendmsg_fds(vu_dev->sock, msg, size, fds, num_fds);
156}
157
158static int vhost_user_send_no_payload(struct virtio_uml_device *vu_dev,
159 u32 request)
160{
161 struct vhost_user_msg msg = {
162 .header.request = request,
163 };
164
165 return vhost_user_send(vu_dev, &msg, NULL, 0);
166}
167
168static int vhost_user_send_u64(struct virtio_uml_device *vu_dev,
169 u32 request, u64 value)
170{
171 struct vhost_user_msg msg = {
172 .header.request = request,
173 .header.size = sizeof(msg.payload.integer),
174 .payload.integer = value,
175 };
176
177 return vhost_user_send(vu_dev, &msg, NULL, 0);
178}
179
180static int vhost_user_set_owner(struct virtio_uml_device *vu_dev)
181{
182 return vhost_user_send_no_payload(vu_dev, VHOST_USER_SET_OWNER);
183}
184
185static int vhost_user_get_features(struct virtio_uml_device *vu_dev,
186 u64 *features)
187{
188 int rc = vhost_user_send_no_payload(vu_dev, VHOST_USER_GET_FEATURES);
189
190 if (rc)
191 return rc;
192 return vhost_user_recv_u64(vu_dev, features);
193}
194
195static int vhost_user_set_features(struct virtio_uml_device *vu_dev,
196 u64 features)
197{
198 return vhost_user_send_u64(vu_dev, VHOST_USER_SET_FEATURES, features);
199}
200
201static int vhost_user_get_protocol_features(struct virtio_uml_device *vu_dev,
202 u64 *protocol_features)
203{
204 int rc = vhost_user_send_no_payload(vu_dev,
205 VHOST_USER_GET_PROTOCOL_FEATURES);
206
207 if (rc)
208 return rc;
209 return vhost_user_recv_u64(vu_dev, protocol_features);
210}
211
212static int vhost_user_set_protocol_features(struct virtio_uml_device *vu_dev,
213 u64 protocol_features)
214{
215 return vhost_user_send_u64(vu_dev, VHOST_USER_SET_PROTOCOL_FEATURES,
216 protocol_features);
217}
218
219static int vhost_user_init(struct virtio_uml_device *vu_dev)
220{
221 int rc = vhost_user_set_owner(vu_dev);
222
223 if (rc)
224 return rc;
225 rc = vhost_user_get_features(vu_dev, &vu_dev->features);
226 if (rc)
227 return rc;
228
229 if (vu_dev->features & BIT_ULL(VHOST_USER_F_PROTOCOL_FEATURES)) {
230 rc = vhost_user_get_protocol_features(vu_dev,
231 &vu_dev->protocol_features);
232 if (rc)
233 return rc;
234 vu_dev->protocol_features &= VHOST_USER_SUPPORTED_PROTOCOL_F;
235 rc = vhost_user_set_protocol_features(vu_dev,
236 vu_dev->protocol_features);
237 }
238 return rc;
239}
240
241static void vhost_user_get_config(struct virtio_uml_device *vu_dev,
242 u32 offset, void *buf, u32 len)
243{
244 u32 cfg_size = offset + len;
245 struct vhost_user_msg *msg;
246 size_t payload_size = sizeof(msg->payload.config) + cfg_size;
247 size_t msg_size = sizeof(msg->header) + payload_size;
248 int rc;
249
250 if (!(vu_dev->protocol_features &
251 BIT_ULL(VHOST_USER_PROTOCOL_F_CONFIG)))
252 return;
253
254 msg = kzalloc(msg_size, GFP_KERNEL);
255 if (!msg)
256 return;
257 msg->header.request = VHOST_USER_GET_CONFIG;
258 msg->header.size = payload_size;
259 msg->payload.config.offset = 0;
260 msg->payload.config.size = cfg_size;
261
262 rc = vhost_user_send(vu_dev, msg, NULL, 0);
263 if (rc) {
264 vu_err(vu_dev, "sending VHOST_USER_GET_CONFIG failed: %d\n",
265 rc);
266 goto free;
267 }
268
269 rc = vhost_user_recv(vu_dev, msg, msg_size);
270 if (rc) {
271 vu_err(vu_dev,
272 "receiving VHOST_USER_GET_CONFIG response failed: %d\n",
273 rc);
274 goto free;
275 }
276
277 if (msg->header.size != payload_size ||
278 msg->payload.config.size != cfg_size) {
279 rc = -EPROTO;
280 vu_err(vu_dev,
281 "Invalid VHOST_USER_GET_CONFIG sizes (payload %d expected %zu, config %u expected %u)\n",
282 msg->header.size, payload_size,
283 msg->payload.config.size, cfg_size);
284 goto free;
285 }
286 memcpy(buf, msg->payload.config.payload + offset, len);
287
288free:
289 kfree(msg);
290}
291
292static void vhost_user_set_config(struct virtio_uml_device *vu_dev,
293 u32 offset, const void *buf, u32 len)
294{
295 struct vhost_user_msg *msg;
296 size_t payload_size = sizeof(msg->payload.config) + len;
297 size_t msg_size = sizeof(msg->header) + payload_size;
298 int rc;
299
300 if (!(vu_dev->protocol_features &
301 BIT_ULL(VHOST_USER_PROTOCOL_F_CONFIG)))
302 return;
303
304 msg = kzalloc(msg_size, GFP_KERNEL);
305 if (!msg)
306 return;
307 msg->header.request = VHOST_USER_SET_CONFIG;
308 msg->header.size = payload_size;
309 msg->payload.config.offset = offset;
310 msg->payload.config.size = len;
311 memcpy(msg->payload.config.payload, buf, len);
312
313 rc = vhost_user_send(vu_dev, msg, NULL, 0);
314 if (rc)
315 vu_err(vu_dev, "sending VHOST_USER_SET_CONFIG failed: %d\n",
316 rc);
317
318 kfree(msg);
319}
320
321static int vhost_user_init_mem_region(u64 addr, u64 size, int *fd_out,
322 struct vhost_user_mem_region *region_out)
323{
324 unsigned long long mem_offset;
325 int rc = phys_mapping(addr, &mem_offset);
326
327 if (WARN(rc < 0, "phys_mapping of 0x%llx returned %d\n", addr, rc))
328 return -EFAULT;
329 *fd_out = rc;
330 region_out->guest_addr = addr;
331 region_out->user_addr = addr;
332 region_out->size = size;
333 region_out->mmap_offset = mem_offset;
334
335 /* Ensure mapping is valid for the entire region */
336 rc = phys_mapping(addr + size - 1, &mem_offset);
337 if (WARN(rc != *fd_out, "phys_mapping of 0x%llx failed: %d != %d\n",
338 addr + size - 1, rc, *fd_out))
339 return -EFAULT;
340 return 0;
341}
342
343static int vhost_user_set_mem_table(struct virtio_uml_device *vu_dev)
344{
345 struct vhost_user_msg msg = {
346 .header.request = VHOST_USER_SET_MEM_TABLE,
347 .header.size = sizeof(msg.payload.mem_regions),
348 .payload.mem_regions.num = 1,
349 };
350 unsigned long reserved = uml_reserved - uml_physmem;
351 int fds[2];
352 int rc;
353
354 /*
355 * This is a bit tricky, see also the comment with setup_physmem().
356 *
357 * Essentially, setup_physmem() uses a file to mmap() our physmem,
358 * but the code and data we *already* have is omitted. To us, this
359 * is no difference, since they both become part of our address
360 * space and memory consumption. To somebody looking in from the
361 * outside, however, it is different because the part of our memory
362 * consumption that's already part of the binary (code/data) is not
363 * mapped from the file, so it's not visible to another mmap from
364 * the file descriptor.
365 *
366 * Thus, don't advertise this space to the vhost-user slave. This
367 * means that the slave will likely abort or similar when we give
368 * it an address from the hidden range, since it's not marked as
369 * a valid address, but at least that way we detect the issue and
370 * don't just have the slave read an all-zeroes buffer from the
371 * shared memory file, or write something there that we can never
372 * see (depending on the direction of the virtqueue traffic.)
373 *
374 * Since we usually don't want to use .text for virtio buffers,
375 * this effectively means that you cannot use
376 * 1) global variables, which are in the .bss and not in the shm
377 * file-backed memory
378 * 2) the stack in some processes, depending on where they have
379 * their stack (or maybe only no interrupt stack?)
380 *
381 * The stack is already not typically valid for DMA, so this isn't
382 * much of a restriction, but global variables might be encountered.
383 *
384 * It might be possible to fix it by copying around the data that's
385 * between bss_start and where we map the file now, but it's not
386 * something that you typically encounter with virtio drivers, so
387 * it didn't seem worthwhile.
388 */
389 rc = vhost_user_init_mem_region(reserved, physmem_size - reserved,
390 &fds[0],
391 &msg.payload.mem_regions.regions[0]);
392
393 if (rc < 0)
394 return rc;
395 if (highmem) {
396 msg.payload.mem_regions.num++;
397 rc = vhost_user_init_mem_region(__pa(end_iomem), highmem,
398 &fds[1], &msg.payload.mem_regions.regions[1]);
399 if (rc < 0)
400 return rc;
401 }
402
403 return vhost_user_send(vu_dev, &msg, fds, msg.payload.mem_regions.num);
404}
405
406static int vhost_user_set_vring_state(struct virtio_uml_device *vu_dev,
407 u32 request, u32 index, u32 num)
408{
409 struct vhost_user_msg msg = {
410 .header.request = request,
411 .header.size = sizeof(msg.payload.vring_state),
412 .payload.vring_state.index = index,
413 .payload.vring_state.num = num,
414 };
415
416 return vhost_user_send(vu_dev, &msg, NULL, 0);
417}
418
419static int vhost_user_set_vring_num(struct virtio_uml_device *vu_dev,
420 u32 index, u32 num)
421{
422 return vhost_user_set_vring_state(vu_dev, VHOST_USER_SET_VRING_NUM,
423 index, num);
424}
425
426static int vhost_user_set_vring_base(struct virtio_uml_device *vu_dev,
427 u32 index, u32 offset)
428{
429 return vhost_user_set_vring_state(vu_dev, VHOST_USER_SET_VRING_BASE,
430 index, offset);
431}
432
433static int vhost_user_set_vring_addr(struct virtio_uml_device *vu_dev,
434 u32 index, u64 desc, u64 used, u64 avail,
435 u64 log)
436{
437 struct vhost_user_msg msg = {
438 .header.request = VHOST_USER_SET_VRING_ADDR,
439 .header.size = sizeof(msg.payload.vring_addr),
440 .payload.vring_addr.index = index,
441 .payload.vring_addr.desc = desc,
442 .payload.vring_addr.used = used,
443 .payload.vring_addr.avail = avail,
444 .payload.vring_addr.log = log,
445 };
446
447 return vhost_user_send(vu_dev, &msg, NULL, 0);
448}
449
450static int vhost_user_set_vring_fd(struct virtio_uml_device *vu_dev,
451 u32 request, int index, int fd)
452{
453 struct vhost_user_msg msg = {
454 .header.request = request,
455 .header.size = sizeof(msg.payload.integer),
456 .payload.integer = index,
457 };
458
459 if (index & ~VHOST_USER_VRING_INDEX_MASK)
460 return -EINVAL;
461 if (fd < 0) {
462 msg.payload.integer |= VHOST_USER_VRING_POLL_MASK;
463 return vhost_user_send(vu_dev, &msg, NULL, 0);
464 }
465 return vhost_user_send(vu_dev, &msg, &fd, 1);
466}
467
468static int vhost_user_set_vring_call(struct virtio_uml_device *vu_dev,
469 int index, int fd)
470{
471 return vhost_user_set_vring_fd(vu_dev, VHOST_USER_SET_VRING_CALL,
472 index, fd);
473}
474
475static int vhost_user_set_vring_kick(struct virtio_uml_device *vu_dev,
476 int index, int fd)
477{
478 return vhost_user_set_vring_fd(vu_dev, VHOST_USER_SET_VRING_KICK,
479 index, fd);
480}
481
482static int vhost_user_set_vring_enable(struct virtio_uml_device *vu_dev,
483 u32 index, bool enable)
484{
485 if (!(vu_dev->features & BIT_ULL(VHOST_USER_F_PROTOCOL_FEATURES)))
486 return 0;
487
488 return vhost_user_set_vring_state(vu_dev, VHOST_USER_SET_VRING_ENABLE,
489 index, enable);
490}
491
492
493/* Virtio interface */
494
495static bool vu_notify(struct virtqueue *vq)
496{
497 struct virtio_uml_vq_info *info = vq->priv;
498 const uint64_t n = 1;
499 int rc;
500
501 do {
502 rc = os_write_file(info->kick_fd, &n, sizeof(n));
503 } while (rc == -EINTR);
504 return !WARN(rc != sizeof(n), "write returned %d\n", rc);
505}
506
507static irqreturn_t vu_interrupt(int irq, void *opaque)
508{
509 struct virtqueue *vq = opaque;
510 struct virtio_uml_vq_info *info = vq->priv;
511 uint64_t n;
512 int rc;
513 irqreturn_t ret = IRQ_NONE;
514
515 do {
516 rc = os_read_file(info->call_fd, &n, sizeof(n));
517 if (rc == sizeof(n))
518 ret |= vring_interrupt(irq, vq);
519 } while (rc == sizeof(n) || rc == -EINTR);
520 WARN(rc != -EAGAIN, "read returned %d\n", rc);
521 return ret;
522}
523
524
525static void vu_get(struct virtio_device *vdev, unsigned offset,
526 void *buf, unsigned len)
527{
528 struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
529
530 vhost_user_get_config(vu_dev, offset, buf, len);
531}
532
533static void vu_set(struct virtio_device *vdev, unsigned offset,
534 const void *buf, unsigned len)
535{
536 struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
537
538 vhost_user_set_config(vu_dev, offset, buf, len);
539}
540
541static u8 vu_get_status(struct virtio_device *vdev)
542{
543 struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
544
545 return vu_dev->status;
546}
547
548static void vu_set_status(struct virtio_device *vdev, u8 status)
549{
550 struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
551
552 vu_dev->status = status;
553}
554
555static void vu_reset(struct virtio_device *vdev)
556{
557 struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
558
559 vu_dev->status = 0;
560}
561
562static void vu_del_vq(struct virtqueue *vq)
563{
564 struct virtio_uml_vq_info *info = vq->priv;
565
566 um_free_irq(VIRTIO_IRQ, vq);
567
568 os_close_file(info->call_fd);
569 os_close_file(info->kick_fd);
570
571 vring_del_virtqueue(vq);
572 kfree(info);
573}
574
575static void vu_del_vqs(struct virtio_device *vdev)
576{
577 struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
578 struct virtqueue *vq, *n;
579 u64 features;
580
581 /* Note: reverse order as a workaround to a decoding bug in snabb */
582 list_for_each_entry_reverse(vq, &vdev->vqs, list)
583 WARN_ON(vhost_user_set_vring_enable(vu_dev, vq->index, false));
584
585 /* Ensure previous messages have been processed */
586 WARN_ON(vhost_user_get_features(vu_dev, &features));
587
588 list_for_each_entry_safe(vq, n, &vdev->vqs, list)
589 vu_del_vq(vq);
590}
591
592static int vu_setup_vq_call_fd(struct virtio_uml_device *vu_dev,
593 struct virtqueue *vq)
594{
595 struct virtio_uml_vq_info *info = vq->priv;
596 int call_fds[2];
597 int rc;
598
599 /* Use a pipe for call fd, since SIGIO is not supported for eventfd */
600 rc = os_pipe(call_fds, true, true);
601 if (rc < 0)
602 return rc;
603
604 info->call_fd = call_fds[0];
605 rc = um_request_irq(VIRTIO_IRQ, info->call_fd, IRQ_READ,
606 vu_interrupt, IRQF_SHARED, info->name, vq);
607 if (rc)
608 goto close_both;
609
610 rc = vhost_user_set_vring_call(vu_dev, vq->index, call_fds[1]);
611 if (rc)
612 goto release_irq;
613
614 goto out;
615
616release_irq:
617 um_free_irq(VIRTIO_IRQ, vq);
618close_both:
619 os_close_file(call_fds[0]);
620out:
621 /* Close (unused) write end of call fds */
622 os_close_file(call_fds[1]);
623
624 return rc;
625}
626
627static struct virtqueue *vu_setup_vq(struct virtio_device *vdev,
628 unsigned index, vq_callback_t *callback,
629 const char *name, bool ctx)
630{
631 struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
632 struct platform_device *pdev = vu_dev->pdev;
633 struct virtio_uml_vq_info *info;
634 struct virtqueue *vq;
635 int num = MAX_SUPPORTED_QUEUE_SIZE;
636 int rc;
637
638 info = kzalloc(sizeof(*info), GFP_KERNEL);
639 if (!info) {
640 rc = -ENOMEM;
641 goto error_kzalloc;
642 }
643 snprintf(info->name, sizeof(info->name), "%s.%d-%s", pdev->name,
644 pdev->id, name);
645
646 vq = vring_create_virtqueue(index, num, PAGE_SIZE, vdev, true, true,
647 ctx, vu_notify, callback, info->name);
648 if (!vq) {
649 rc = -ENOMEM;
650 goto error_create;
651 }
652 vq->priv = info;
653 num = virtqueue_get_vring_size(vq);
654
655 rc = os_eventfd(0, 0);
656 if (rc < 0)
657 goto error_kick;
658 info->kick_fd = rc;
659
660 rc = vu_setup_vq_call_fd(vu_dev, vq);
661 if (rc)
662 goto error_call;
663
664 rc = vhost_user_set_vring_num(vu_dev, index, num);
665 if (rc)
666 goto error_setup;
667
668 rc = vhost_user_set_vring_base(vu_dev, index, 0);
669 if (rc)
670 goto error_setup;
671
672 rc = vhost_user_set_vring_addr(vu_dev, index,
673 virtqueue_get_desc_addr(vq),
674 virtqueue_get_used_addr(vq),
675 virtqueue_get_avail_addr(vq),
676 (u64) -1);
677 if (rc)
678 goto error_setup;
679
680 return vq;
681
682error_setup:
683 um_free_irq(VIRTIO_IRQ, vq);
684 os_close_file(info->call_fd);
685error_call:
686 os_close_file(info->kick_fd);
687error_kick:
688 vring_del_virtqueue(vq);
689error_create:
690 kfree(info);
691error_kzalloc:
692 return ERR_PTR(rc);
693}
694
695static int vu_find_vqs(struct virtio_device *vdev, unsigned nvqs,
696 struct virtqueue *vqs[], vq_callback_t *callbacks[],
697 const char * const names[], const bool *ctx,
698 struct irq_affinity *desc)
699{
700 struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
701 int i, queue_idx = 0, rc;
702 struct virtqueue *vq;
703
704 rc = vhost_user_set_mem_table(vu_dev);
705 if (rc)
706 return rc;
707
708 for (i = 0; i < nvqs; ++i) {
709 if (!names[i]) {
710 vqs[i] = NULL;
711 continue;
712 }
713
714 vqs[i] = vu_setup_vq(vdev, queue_idx++, callbacks[i], names[i],
715 ctx ? ctx[i] : false);
716 if (IS_ERR(vqs[i])) {
717 rc = PTR_ERR(vqs[i]);
718 goto error_setup;
719 }
720 }
721
722 list_for_each_entry(vq, &vdev->vqs, list) {
723 struct virtio_uml_vq_info *info = vq->priv;
724
725 rc = vhost_user_set_vring_kick(vu_dev, vq->index,
726 info->kick_fd);
727 if (rc)
728 goto error_setup;
729
730 rc = vhost_user_set_vring_enable(vu_dev, vq->index, true);
731 if (rc)
732 goto error_setup;
733 }
734
735 return 0;
736
737error_setup:
738 vu_del_vqs(vdev);
739 return rc;
740}
741
742static u64 vu_get_features(struct virtio_device *vdev)
743{
744 struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
745
746 return vu_dev->features;
747}
748
749static int vu_finalize_features(struct virtio_device *vdev)
750{
751 struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
752 u64 supported = vdev->features & VHOST_USER_SUPPORTED_F;
753
754 vring_transport_features(vdev);
755 vu_dev->features = vdev->features | supported;
756
757 return vhost_user_set_features(vu_dev, vu_dev->features);
758}
759
760static const char *vu_bus_name(struct virtio_device *vdev)
761{
762 struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
763
764 return vu_dev->pdev->name;
765}
766
767static const struct virtio_config_ops virtio_uml_config_ops = {
768 .get = vu_get,
769 .set = vu_set,
770 .get_status = vu_get_status,
771 .set_status = vu_set_status,
772 .reset = vu_reset,
773 .find_vqs = vu_find_vqs,
774 .del_vqs = vu_del_vqs,
775 .get_features = vu_get_features,
776 .finalize_features = vu_finalize_features,
777 .bus_name = vu_bus_name,
778};
779
780
781static void virtio_uml_release_dev(struct device *d)
782{
783 struct virtio_device *vdev =
784 container_of(d, struct virtio_device, dev);
785 struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev);
786
787 os_close_file(vu_dev->sock);
788}
789
790/* Platform device */
791
792struct virtio_uml_platform_data {
793 u32 virtio_device_id;
794 const char *socket_path;
795};
796
797static int virtio_uml_probe(struct platform_device *pdev)
798{
799 struct virtio_uml_platform_data *pdata = pdev->dev.platform_data;
800 struct virtio_uml_device *vu_dev;
801 int rc;
802
803 if (!pdata)
804 return -EINVAL;
805
806 vu_dev = devm_kzalloc(&pdev->dev, sizeof(*vu_dev), GFP_KERNEL);
807 if (!vu_dev)
808 return -ENOMEM;
809
810 vu_dev->vdev.dev.parent = &pdev->dev;
811 vu_dev->vdev.dev.release = virtio_uml_release_dev;
812 vu_dev->vdev.config = &virtio_uml_config_ops;
813 vu_dev->vdev.id.device = pdata->virtio_device_id;
814 vu_dev->vdev.id.vendor = VIRTIO_DEV_ANY_ID;
815 vu_dev->pdev = pdev;
816
817 do {
818 rc = os_connect_socket(pdata->socket_path);
819 } while (rc == -EINTR);
820 if (rc < 0)
821 return rc;
822 vu_dev->sock = rc;
823
824 rc = vhost_user_init(vu_dev);
825 if (rc)
826 goto error_init;
827
828 platform_set_drvdata(pdev, vu_dev);
829
830 rc = register_virtio_device(&vu_dev->vdev);
831 if (rc)
832 put_device(&vu_dev->vdev.dev);
833 return rc;
834
835error_init:
836 os_close_file(vu_dev->sock);
837 return rc;
838}
839
840static int virtio_uml_remove(struct platform_device *pdev)
841{
842 struct virtio_uml_device *vu_dev = platform_get_drvdata(pdev);
843
844 unregister_virtio_device(&vu_dev->vdev);
845 return 0;
846}
847
848/* Command line device list */
849
850static void vu_cmdline_release_dev(struct device *d)
851{
852}
853
854static struct device vu_cmdline_parent = {
855 .init_name = "virtio-uml-cmdline",
856 .release = vu_cmdline_release_dev,
857};
858
859static bool vu_cmdline_parent_registered;
860static int vu_cmdline_id;
861
862static int vu_cmdline_set(const char *device, const struct kernel_param *kp)
863{
864 const char *ids = strchr(device, ':');
865 unsigned int virtio_device_id;
866 int processed, consumed, err;
867 char *socket_path;
868 struct virtio_uml_platform_data pdata;
869 struct platform_device *pdev;
870
871 if (!ids || ids == device)
872 return -EINVAL;
873
874 processed = sscanf(ids, ":%u%n:%d%n",
875 &virtio_device_id, &consumed,
876 &vu_cmdline_id, &consumed);
877
878 if (processed < 1 || ids[consumed])
879 return -EINVAL;
880
881 if (!vu_cmdline_parent_registered) {
882 err = device_register(&vu_cmdline_parent);
883 if (err) {
884 pr_err("Failed to register parent device!\n");
885 put_device(&vu_cmdline_parent);
886 return err;
887 }
888 vu_cmdline_parent_registered = true;
889 }
890
891 socket_path = kmemdup_nul(device, ids - device, GFP_KERNEL);
892 if (!socket_path)
893 return -ENOMEM;
894
895 pdata.virtio_device_id = (u32) virtio_device_id;
896 pdata.socket_path = socket_path;
897
898 pr_info("Registering device virtio-uml.%d id=%d at %s\n",
899 vu_cmdline_id, virtio_device_id, socket_path);
900
901 pdev = platform_device_register_data(&vu_cmdline_parent, "virtio-uml",
902 vu_cmdline_id++, &pdata,
903 sizeof(pdata));
904 err = PTR_ERR_OR_ZERO(pdev);
905 if (err)
906 goto free;
907 return 0;
908
909free:
910 kfree(socket_path);
911 return err;
912}
913
914static int vu_cmdline_get_device(struct device *dev, void *data)
915{
916 struct platform_device *pdev = to_platform_device(dev);
917 struct virtio_uml_platform_data *pdata = pdev->dev.platform_data;
918 char *buffer = data;
919 unsigned int len = strlen(buffer);
920
921 snprintf(buffer + len, PAGE_SIZE - len, "%s:%d:%d\n",
922 pdata->socket_path, pdata->virtio_device_id, pdev->id);
923 return 0;
924}
925
926static int vu_cmdline_get(char *buffer, const struct kernel_param *kp)
927{
928 buffer[0] = '\0';
929 if (vu_cmdline_parent_registered)
930 device_for_each_child(&vu_cmdline_parent, buffer,
931 vu_cmdline_get_device);
932 return strlen(buffer) + 1;
933}
934
935static const struct kernel_param_ops vu_cmdline_param_ops = {
936 .set = vu_cmdline_set,
937 .get = vu_cmdline_get,
938};
939
940device_param_cb(device, &vu_cmdline_param_ops, NULL, S_IRUSR);
941__uml_help(vu_cmdline_param_ops,
942"virtio_uml.device=<socket>:<virtio_id>[:<platform_id>]\n"
943" Configure a virtio device over a vhost-user socket.\n"
944" See virtio_ids.h for a list of possible virtio device id values.\n"
945" Optionally use a specific platform_device id.\n\n"
946);
947
948
949static int vu_unregister_cmdline_device(struct device *dev, void *data)
950{
951 struct platform_device *pdev = to_platform_device(dev);
952 struct virtio_uml_platform_data *pdata = pdev->dev.platform_data;
953
954 kfree(pdata->socket_path);
955 platform_device_unregister(pdev);
956 return 0;
957}
958
959static void vu_unregister_cmdline_devices(void)
960{
961 if (vu_cmdline_parent_registered) {
962 device_for_each_child(&vu_cmdline_parent, NULL,
963 vu_unregister_cmdline_device);
964 device_unregister(&vu_cmdline_parent);
965 vu_cmdline_parent_registered = false;
966 }
967}
968
969/* Platform driver */
970
971static const struct of_device_id virtio_uml_match[] = {
972 { .compatible = "virtio,uml", },
973 { }
974};
975MODULE_DEVICE_TABLE(of, virtio_uml_match);
976
977static struct platform_driver virtio_uml_driver = {
978 .probe = virtio_uml_probe,
979 .remove = virtio_uml_remove,
980 .driver = {
981 .name = "virtio-uml",
982 .of_match_table = virtio_uml_match,
983 },
984};
985
986static int __init virtio_uml_init(void)
987{
988 return platform_driver_register(&virtio_uml_driver);
989}
990
991static void __exit virtio_uml_exit(void)
992{
993 platform_driver_unregister(&virtio_uml_driver);
994 vu_unregister_cmdline_devices();
995}
996
997module_init(virtio_uml_init);
998module_exit(virtio_uml_exit);
999__uml_exitcall(virtio_uml_exit);
1000
1001MODULE_DESCRIPTION("UML driver for vhost-user virtio devices");
1002MODULE_LICENSE("GPL");
diff --git a/arch/um/include/asm/irq.h b/arch/um/include/asm/irq.h
index ce7a78c3bcf2..42c6205e2dc4 100644
--- a/arch/um/include/asm/irq.h
+++ b/arch/um/include/asm/irq.h
@@ -17,17 +17,18 @@
17#define TELNETD_IRQ 12 17#define TELNETD_IRQ 12
18#define XTERM_IRQ 13 18#define XTERM_IRQ 13
19#define RANDOM_IRQ 14 19#define RANDOM_IRQ 14
20#define VIRTIO_IRQ 15
20 21
21#ifdef CONFIG_UML_NET_VECTOR 22#ifdef CONFIG_UML_NET_VECTOR
22 23
23#define VECTOR_BASE_IRQ 15 24#define VECTOR_BASE_IRQ (VIRTIO_IRQ + 1)
24#define VECTOR_IRQ_SPACE 8 25#define VECTOR_IRQ_SPACE 8
25 26
26#define LAST_IRQ (VECTOR_IRQ_SPACE + VECTOR_BASE_IRQ - 1) 27#define LAST_IRQ (VECTOR_IRQ_SPACE + VECTOR_BASE_IRQ - 1)
27 28
28#else 29#else
29 30
30#define LAST_IRQ RANDOM_IRQ 31#define LAST_IRQ VIRTIO_IRQ
31 32
32#endif 33#endif
33 34
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
index fa1909365666..d542dadcf22e 100644
--- a/arch/um/include/shared/os.h
+++ b/arch/um/include/shared/os.h
@@ -36,6 +36,8 @@
36#define OS_LIB_PATH "/usr/lib/" 36#define OS_LIB_PATH "/usr/lib/"
37#endif 37#endif
38 38
39#define OS_SENDMSG_MAX_FDS 8
40
39/* 41/*
40 * types taken from stat_file() in hostfs_user.c 42 * types taken from stat_file() in hostfs_user.c
41 * (if they are wrong here, they are wrong there...). 43 * (if they are wrong here, they are wrong there...).
@@ -176,6 +178,9 @@ extern unsigned os_major(unsigned long long dev);
176extern unsigned os_minor(unsigned long long dev); 178extern unsigned os_minor(unsigned long long dev);
177extern unsigned long long os_makedev(unsigned major, unsigned minor); 179extern unsigned long long os_makedev(unsigned major, unsigned minor);
178extern int os_falloc_punch(int fd, unsigned long long offset, int count); 180extern int os_falloc_punch(int fd, unsigned long long offset, int count);
181extern int os_eventfd(unsigned int initval, int flags);
182extern int os_sendmsg_fds(int fd, const void *buf, unsigned int len,
183 const int *fds, unsigned int fds_num);
179 184
180/* start_up.c */ 185/* start_up.c */
181extern void os_early_checks(void); 186extern void os_early_checks(void);
diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c
index 232b22307fdd..bdb90583f186 100644
--- a/arch/um/kernel/ksyms.c
+++ b/arch/um/kernel/ksyms.c
@@ -38,6 +38,8 @@ EXPORT_SYMBOL(run_helper);
38EXPORT_SYMBOL(os_major); 38EXPORT_SYMBOL(os_major);
39EXPORT_SYMBOL(os_minor); 39EXPORT_SYMBOL(os_minor);
40EXPORT_SYMBOL(os_makedev); 40EXPORT_SYMBOL(os_makedev);
41EXPORT_SYMBOL(os_eventfd);
42EXPORT_SYMBOL(os_sendmsg_fds);
41 43
42EXPORT_SYMBOL(add_sigio_fd); 44EXPORT_SYMBOL(add_sigio_fd);
43EXPORT_SYMBOL(ignore_sigio_fd); 45EXPORT_SYMBOL(ignore_sigio_fd);
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index de58e976b9bc..f256be1d77bd 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -31,6 +31,7 @@ pgd_t swapper_pg_dir[PTRS_PER_PGD];
31 31
32/* Initialized at boot time, and readonly after that */ 32/* Initialized at boot time, and readonly after that */
33unsigned long long highmem; 33unsigned long long highmem;
34EXPORT_SYMBOL(highmem);
34int kmalloc_ok = 0; 35int kmalloc_ok = 0;
35 36
36/* Used during early boot */ 37/* Used during early boot */
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
index 5bf56af4d5b9..870c80c88a97 100644
--- a/arch/um/kernel/physmem.c
+++ b/arch/um/kernel/physmem.c
@@ -143,6 +143,7 @@ int phys_mapping(unsigned long phys, unsigned long long *offset_out)
143 143
144 return fd; 144 return fd;
145} 145}
146EXPORT_SYMBOL(phys_mapping);
146 147
147static int __init uml_mem_setup(char *line, int *add) 148static int __init uml_mem_setup(char *line, int *add)
148{ 149{
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index a818ccef30ca..9de212bf4320 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -113,6 +113,7 @@ static int have_root __initdata = 0;
113 113
114/* Set in uml_mem_setup and modified in linux_main */ 114/* Set in uml_mem_setup and modified in linux_main */
115long long physmem_size = 32 * 1024 * 1024; 115long long physmem_size = 32 * 1024 * 1024;
116EXPORT_SYMBOL(physmem_size);
116 117
117static const char *usage_string = 118static const char *usage_string =
118"User Mode Linux v%s\n" 119"User Mode Linux v%s\n"
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
index f25b110d4e70..91f23035be08 100644
--- a/arch/um/os-Linux/file.c
+++ b/arch/um/os-Linux/file.c
@@ -15,6 +15,7 @@
15#include <sys/sysmacros.h> 15#include <sys/sysmacros.h>
16#include <sys/un.h> 16#include <sys/un.h>
17#include <sys/types.h> 17#include <sys/types.h>
18#include <sys/eventfd.h>
18#include <os.h> 19#include <os.h>
19 20
20static void copy_stat(struct uml_stat *dst, const struct stat64 *src) 21static void copy_stat(struct uml_stat *dst, const struct stat64 *src)
@@ -620,3 +621,46 @@ int os_falloc_punch(int fd, unsigned long long offset, int len)
620 return n; 621 return n;
621} 622}
622 623
624int os_eventfd(unsigned int initval, int flags)
625{
626 int fd = eventfd(initval, flags);
627
628 if (fd < 0)
629 return -errno;
630 return fd;
631}
632
633int os_sendmsg_fds(int fd, const void *buf, unsigned int len, const int *fds,
634 unsigned int fds_num)
635{
636 struct iovec iov = {
637 .iov_base = (void *) buf,
638 .iov_len = len,
639 };
640 union {
641 char control[CMSG_SPACE(sizeof(*fds) * OS_SENDMSG_MAX_FDS)];
642 struct cmsghdr align;
643 } u;
644 unsigned int fds_size = sizeof(*fds) * fds_num;
645 struct msghdr msg = {
646 .msg_iov = &iov,
647 .msg_iovlen = 1,
648 .msg_control = u.control,
649 .msg_controllen = CMSG_SPACE(fds_size),
650 };
651 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
652 int err;
653
654 if (fds_num > OS_SENDMSG_MAX_FDS)
655 return -EINVAL;
656 memset(u.control, 0, sizeof(u.control));
657 cmsg->cmsg_level = SOL_SOCKET;
658 cmsg->cmsg_type = SCM_RIGHTS;
659 cmsg->cmsg_len = CMSG_LEN(fds_size);
660 memcpy(CMSG_DATA(cmsg), fds, fds_size);
661 err = sendmsg(fd, &msg, 0);
662
663 if (err < 0)
664 return -errno;
665 return err;
666}