History

xen: privcmd: Add support for ioeventfd

Virtio guests send VIRTIO_MMIO_QUEUE_NOTIFY notification when they need to notify the backend of an update to the status of the virtqueue. The backend or another entity, polls the MMIO address for updates to know when the notification is sent. It works well if the backend does this polling by itself. But as we move towards generic backend implementations, we end up implementing this in a separate user-space program. Generally, the Virtio backends are implemented to work with the Eventfd based mechanism. In order to make such backends work with Xen, another software layer needs to do the polling and send an event via eventfd to the backend once the notification from guest is received. This results in an extra context switch. This is not a new problem in Linux though. It is present with other hypervisors like KVM, etc. as well. The generic solution implemented in the kernel for them is to provide an IOCTL call to pass the address to poll and eventfd, which lets the kernel take care of polling and raise an event on the eventfd, instead of handling this in user space (which involves an extra context switch). This patch adds similar support for xen. Inspired by existing implementations for KVM, etc.. This also copies ioreq.h header file (only struct ioreq and related macros) from Xen's source tree (Top commit 5d84f07fe6bf ("xen/pci: drop remaining uses of bool_t")).

Viresh Kumar committed 3 years ago

Commit f0d7db71 parent 9e90e584 files · +476 −6Browse files

Unified · Split

4 files
  1. drivers/xen/Kconfig +4 −4
  2. drivers/xen/privcmd.c +403 −2
  3. include/uapi/xen/privcmd.h +18 −0
  4. include/xen/interface/hvm/ioreq.h +51 −0
drivers/xen/Kconfig+4−4
@@ -269,12 +269,12 @@ config XEN_PRIVCMD · 268 unmodified lines
269269 disaggregated Xen setups this driver might be needed for other
270270 domains, too.
271271
272−config XEN_PRIVCMD_IRQFD
273− bool "Xen irqfd support"
272+config XEN_PRIVCMD_EVENTFD
273+ bool "Xen Ioeventfd and irqfd support"
274274 depends on XEN_PRIVCMD && XEN_VIRTIO && EVENTFD
275275 help
276− Using the irqfd mechanism a virtio backend running in a daemon can
277− speed up interrupt injection into a guest.
276+ Using the ioeventfd / irqfd mechanism a virtio backend running in a
277+ daemon can speed up interrupt delivery from / to a guest.
278278
279279 config XEN_ACPI_PROCESSOR
280280 tristate "Xen ACPI processor"
drivers/xen/privcmd.c+403−2
@@ -29,15 +29,18 @@ · 28 unmodified lines
2929 #include <linux/seq_file.h>
3030 #include <linux/miscdevice.h>
3131 #include <linux/moduleparam.h>
32+#include <linux/virtio_mmio.h>
3233
3334 #include <asm/xen/hypervisor.h>
3435 #include <asm/xen/hypercall.h>
3536
3637 #include <xen/xen.h>
38+#include <xen/events.h>
3739 #include <xen/privcmd.h>
3840 #include <xen/interface/xen.h>
3941 #include <xen/interface/memory.h>
4042 #include <xen/interface/hvm/dm_op.h>
43+#include <xen/interface/hvm/ioreq.h>
4144 #include <xen/features.h>
4245 #include <xen/page.h>
4346 #include <xen/xen-ops.h>
@@ -782,6 +785,7 @@ static long privcmd_ioctl_mmap_resource(struct file *file, · 738 unmodified lines
782785 goto out;
783786
784787 pages = vma->vm_private_data;
788+
785789 for (i = 0; i < kdata.num; i++) {
786790 xen_pfn_t pfn =
787791 page_to_xen_pfn(pages[i / XEN_PFN_PER_PAGE]);
@@ -838,7 +842,7 @@ out: · 50 unmodified lines
838842 return rc;
839843 }
840844
841−#ifdef CONFIG_XEN_PRIVCMD_IRQFD
845+#ifdef CONFIG_XEN_PRIVCMD_EVENTFD
842846 /* Irqfd support */
843847 static struct workqueue_struct *irqfd_cleanup_wq;
844848 static DEFINE_MUTEX(irqfds_lock);
@@ -1079,6 +1083,389 @@ static void privcmd_irqfd_exit(void) · 234 unmodified lines
10791083
10801084 destroy_workqueue(irqfd_cleanup_wq);
10811085 }
1086+
1087+/* Ioeventfd Support */
1088+#define QUEUE_NOTIFY_VQ_MASK 0xFFFF
1089+
1090+static DEFINE_MUTEX(ioreq_lock);
1091+static LIST_HEAD(ioreq_list);
1092+
1093+/* per-eventfd structure */
1094+struct privcmd_kernel_ioeventfd {
1095+ struct eventfd_ctx *eventfd;
1096+ struct list_head list;
1097+ u64 addr;
1098+ unsigned int addr_len;
1099+ unsigned int vq;
1100+};
1101+
1102+/* per-guest CPU / port structure */
1103+struct ioreq_port {
1104+ int vcpu;
1105+ unsigned int port;
1106+ struct privcmd_kernel_ioreq *kioreq;
1107+};
1108+
1109+/* per-guest structure */
1110+struct privcmd_kernel_ioreq {
1111+ domid_t dom;
1112+ unsigned int vcpus;
1113+ u64 uioreq;
1114+ struct ioreq *ioreq;
1115+ spinlock_t lock; /* Protects ioeventfds list */
1116+ struct list_head ioeventfds;
1117+ struct list_head list;
1118+ struct ioreq_port ports[0];
1119+};
1120+
1121+static irqreturn_t ioeventfd_interrupt(int irq, void *dev_id)
1122+{
1123+ struct ioreq_port *port = dev_id;
1124+ struct privcmd_kernel_ioreq *kioreq = port->kioreq;
1125+ struct ioreq *ioreq = &kioreq->ioreq[port->vcpu];
1126+ struct privcmd_kernel_ioeventfd *kioeventfd;
1127+ unsigned int state = STATE_IOREQ_READY;
1128+
1129+ if (ioreq->state != STATE_IOREQ_READY ||
1130+ ioreq->type != IOREQ_TYPE_COPY || ioreq->dir != IOREQ_WRITE)
1131+ return IRQ_NONE;
1132+
1133+ /*
1134+ * We need a barrier, smp_mb(), here to ensure reads are finished before
1135+ * `state` is updated. Since the lock implementation ensures that
1136+ * appropriate barrier will be added anyway, we can avoid adding
1137+ * explicit barrier here.
1138+ *
1139+ * Ideally we don't need to update `state` within the locks, but we do
1140+ * that here to avoid adding explicit barrier.
1141+ */
1142+
1143+ spin_lock(&kioreq->lock);
1144+ ioreq->state = STATE_IOREQ_INPROCESS;
1145+
1146+ list_for_each_entry(kioeventfd, &kioreq->ioeventfds, list) {
1147+ if (ioreq->addr == kioeventfd->addr + VIRTIO_MMIO_QUEUE_NOTIFY &&
1148+ ioreq->size == kioeventfd->addr_len &&
1149+ (ioreq->data & QUEUE_NOTIFY_VQ_MASK) == kioeventfd->vq) {
1150+ eventfd_signal(kioeventfd->eventfd, 1);
1151+ state = STATE_IORESP_READY;
1152+ break;
1153+ }
1154+ }
1155+ spin_unlock(&kioreq->lock);
1156+
1157+ /*
1158+ * We need a barrier, smp_mb(), here to ensure writes are finished
1159+ * before `state` is updated. Since the lock implementation ensures that
1160+ * appropriate barrier will be added anyway, we can avoid adding
1161+ * explicit barrier here.
1162+ */
1163+
1164+ ioreq->state = state;
1165+
1166+ if (state == STATE_IORESP_READY) {
1167+ notify_remote_via_evtchn(port->port);
1168+ return IRQ_HANDLED;
1169+ }
1170+
1171+ return IRQ_NONE;
1172+}
1173+
1174+static void ioreq_free(struct privcmd_kernel_ioreq *kioreq)
1175+{
1176+ struct ioreq_port *ports = kioreq->ports;
1177+ int i;
1178+
1179+ lockdep_assert_held(&ioreq_lock);
1180+
1181+ list_del(&kioreq->list);
1182+
1183+ for (i = kioreq->vcpus - 1; i >= 0; i--)
1184+ unbind_from_irqhandler(irq_from_evtchn(ports[i].port), &ports[i]);
1185+
1186+ kfree(kioreq);
1187+}
1188+
1189+static
1190+struct privcmd_kernel_ioreq *alloc_ioreq(struct privcmd_ioeventfd *ioeventfd)
1191+{
1192+ struct privcmd_kernel_ioreq *kioreq;
1193+ struct mm_struct *mm = current->mm;
1194+ struct vm_area_struct *vma;
1195+ struct page **pages;
1196+ unsigned int *ports;
1197+ int ret, size, i;
1198+
1199+ lockdep_assert_held(&ioreq_lock);
1200+
1201+ size = struct_size(kioreq, ports, ioeventfd->vcpus);
1202+ kioreq = kzalloc(size, GFP_KERNEL);
1203+ if (!kioreq)
1204+ return ERR_PTR(-ENOMEM);
1205+
1206+ kioreq->dom = ioeventfd->dom;
1207+ kioreq->vcpus = ioeventfd->vcpus;
1208+ kioreq->uioreq = ioeventfd->ioreq;
1209+ spin_lock_init(&kioreq->lock);
1210+ INIT_LIST_HEAD(&kioreq->ioeventfds);
1211+
1212+ /* The memory for ioreq server must have been mapped earlier */
1213+ mmap_write_lock(mm);
1214+ vma = find_vma(mm, (unsigned long)ioeventfd->ioreq);
1215+ if (!vma) {
1216+ pr_err("Failed to find vma for ioreq page!\n");
1217+ mmap_write_unlock(mm);
1218+ ret = -EFAULT;
1219+ goto error_kfree;
1220+ }
1221+
1222+ pages = vma->vm_private_data;
1223+ kioreq->ioreq = (struct ioreq *)(page_to_virt(pages[0]));
1224+ mmap_write_unlock(mm);
1225+
1226+ size = sizeof(*ports) * kioreq->vcpus;
1227+ ports = kzalloc(size, GFP_KERNEL);
1228+ if (!ports) {
1229+ ret = -ENOMEM;
1230+ goto error_kfree;
1231+ }
1232+
1233+ if (copy_from_user(ports, u64_to_user_ptr(ioeventfd->ports), size)) {
1234+ ret = -EFAULT;
1235+ goto error_kfree_ports;
1236+ }
1237+
1238+ for (i = 0; i < kioreq->vcpus; i++) {
1239+ kioreq->ports[i].vcpu = i;
1240+ kioreq->ports[i].port = ports[i];
1241+ kioreq->ports[i].kioreq = kioreq;
1242+
1243+ ret = bind_evtchn_to_irqhandler_lateeoi(ports[i],
1244+ ioeventfd_interrupt, IRQF_SHARED, "ioeventfd",
1245+ &kioreq->ports[i]);
1246+ if (ret < 0)
1247+ goto error_unbind;
1248+ }
1249+
1250+ kfree(ports);
1251+
1252+ list_add_tail(&kioreq->list, &ioreq_list);
1253+
1254+ return kioreq;
1255+
1256+error_unbind:
1257+ while (--i >= 0)
1258+ unbind_from_irqhandler(irq_from_evtchn(ports[i]), &kioreq->ports[i]);
1259+error_kfree_ports:
1260+ kfree(ports);
1261+error_kfree:
1262+ kfree(kioreq);
1263+ return ERR_PTR(ret);
1264+}
1265+
1266+static struct privcmd_kernel_ioreq *
1267+get_ioreq(struct privcmd_ioeventfd *ioeventfd, struct eventfd_ctx *eventfd)
1268+{
1269+ struct privcmd_kernel_ioreq *kioreq;
1270+ unsigned long flags;
1271+
1272+ list_for_each_entry(kioreq, &ioreq_list, list) {
1273+ struct privcmd_kernel_ioeventfd *kioeventfd;
1274+
1275+ /*
1276+ * kioreq fields can be accessed here without a lock as they are
1277+ * never updated after being added to the ioreq_list.
1278+ */
1279+ if (kioreq->uioreq != ioeventfd->ioreq) {
1280+ continue;
1281+ } else if (kioreq->dom != ioeventfd->dom ||
1282+ kioreq->vcpus != ioeventfd->vcpus) {
1283+ pr_err("Invalid ioeventfd configuration mismatch, dom (%u vs %u), vcpus (%u vs %u)\n",
1284+ kioreq->dom, ioeventfd->dom, kioreq->vcpus,
1285+ ioeventfd->vcpus);
1286+ return ERR_PTR(-EINVAL);
1287+ }
1288+
1289+ /* Look for a duplicate eventfd for the same guest */
1290+ spin_lock_irqsave(&kioreq->lock, flags);
1291+ list_for_each_entry(kioeventfd, &kioreq->ioeventfds, list) {
1292+ if (eventfd == kioeventfd->eventfd) {
1293+ spin_unlock_irqrestore(&kioreq->lock, flags);
1294+ return ERR_PTR(-EBUSY);
1295+ }
1296+ }
1297+ spin_unlock_irqrestore(&kioreq->lock, flags);
1298+
1299+ return kioreq;
1300+ }
1301+
1302+ /* Matching kioreq isn't found, allocate a new one */
1303+ return alloc_ioreq(ioeventfd);
1304+}
1305+
1306+static void ioeventfd_free(struct privcmd_kernel_ioeventfd *kioeventfd)
1307+{
1308+ list_del(&kioeventfd->list);
1309+ eventfd_ctx_put(kioeventfd->eventfd);
1310+ kfree(kioeventfd);
1311+}
1312+
1313+static int privcmd_ioeventfd_assign(struct privcmd_ioeventfd *ioeventfd)
1314+{
1315+ struct privcmd_kernel_ioeventfd *kioeventfd;
1316+ struct privcmd_kernel_ioreq *kioreq;
1317+ unsigned long flags;
1318+ struct fd f;
1319+ int ret;
1320+
1321+ /* Check for range overflow */
1322+ if (ioeventfd->addr + ioeventfd->addr_len < ioeventfd->addr)
1323+ return -EINVAL;
1324+
1325+ /* Vhost requires us to support length 1, 2, 4, and 8 */
1326+ if (!(ioeventfd->addr_len == 1 || ioeventfd->addr_len == 2 ||
1327+ ioeventfd->addr_len == 4 || ioeventfd->addr_len == 8))
1328+ return -EINVAL;
1329+
1330+ /* 4096 vcpus limit enough ? */
1331+ if (!ioeventfd->vcpus || ioeventfd->vcpus > 4096)
1332+ return -EINVAL;
1333+
1334+ kioeventfd = kzalloc(sizeof(*kioeventfd), GFP_KERNEL);
1335+ if (!kioeventfd)
1336+ return -ENOMEM;
1337+
1338+ f = fdget(ioeventfd->event_fd);
1339+ if (!f.file) {
1340+ ret = -EBADF;
1341+ goto error_kfree;
1342+ }
1343+
1344+ kioeventfd->eventfd = eventfd_ctx_fileget(f.file);
1345+ fdput(f);
1346+
1347+ if (IS_ERR(kioeventfd->eventfd)) {
1348+ ret = PTR_ERR(kioeventfd->eventfd);
1349+ goto error_kfree;
1350+ }
1351+
1352+ kioeventfd->addr = ioeventfd->addr;
1353+ kioeventfd->addr_len = ioeventfd->addr_len;
1354+ kioeventfd->vq = ioeventfd->vq;
1355+
1356+ mutex_lock(&ioreq_lock);
1357+ kioreq = get_ioreq(ioeventfd, kioeventfd->eventfd);
1358+ if (IS_ERR(kioreq)) {
1359+ mutex_unlock(&ioreq_lock);
1360+ ret = PTR_ERR(kioreq);
1361+ goto error_eventfd;
1362+ }
1363+
1364+ spin_lock_irqsave(&kioreq->lock, flags);
1365+ list_add_tail(&kioeventfd->list, &kioreq->ioeventfds);
1366+ spin_unlock_irqrestore(&kioreq->lock, flags);
1367+
1368+ mutex_unlock(&ioreq_lock);
1369+
1370+ return 0;
1371+
1372+error_eventfd:
1373+ eventfd_ctx_put(kioeventfd->eventfd);
1374+
1375+error_kfree:
1376+ kfree(kioeventfd);
1377+ return ret;
1378+}
1379+
1380+static int privcmd_ioeventfd_deassign(struct privcmd_ioeventfd *ioeventfd)
1381+{
1382+ struct privcmd_kernel_ioreq *kioreq, *tkioreq;
1383+ struct eventfd_ctx *eventfd;
1384+ unsigned long flags;
1385+ int ret = 0;
1386+
1387+ eventfd = eventfd_ctx_fdget(ioeventfd->event_fd);
1388+ if (IS_ERR(eventfd))
1389+ return PTR_ERR(eventfd);
1390+
1391+ mutex_lock(&ioreq_lock);
1392+ list_for_each_entry_safe(kioreq, tkioreq, &ioreq_list, list) {
1393+ struct privcmd_kernel_ioeventfd *kioeventfd, *tmp;
1394+ /*
1395+ * kioreq fields can be accessed here without a lock as they are
1396+ * never updated after being added to the ioreq_list.
1397+ */
1398+ if (kioreq->dom != ioeventfd->dom ||
1399+ kioreq->uioreq != ioeventfd->ioreq ||
1400+ kioreq->vcpus != ioeventfd->vcpus)
1401+ continue;
1402+
1403+ spin_lock_irqsave(&kioreq->lock, flags);
1404+ list_for_each_entry_safe(kioeventfd, tmp, &kioreq->ioeventfds, list) {
1405+ if (eventfd == kioeventfd->eventfd) {
1406+ ioeventfd_free(kioeventfd);
1407+ spin_unlock_irqrestore(&kioreq->lock, flags);
1408+
1409+ if (list_empty(&kioreq->ioeventfds))
1410+ ioreq_free(kioreq);
1411+ goto unlock;
1412+ }
1413+ }
1414+ spin_unlock_irqrestore(&kioreq->lock, flags);
1415+ break;
1416+ }
1417+
1418+ pr_err("Ioeventfd isn't already assigned, dom: %u, addr: %llu\n",
1419+ ioeventfd->dom, ioeventfd->addr);
1420+ ret = -ENODEV;
1421+
1422+unlock:
1423+ mutex_unlock(&ioreq_lock);
1424+ eventfd_ctx_put(eventfd);
1425+
1426+ return ret;
1427+}
1428+
1429+static long privcmd_ioctl_ioeventfd(struct file *file, void __user *udata)
1430+{
1431+ struct privcmd_data *data = file->private_data;
1432+ struct privcmd_ioeventfd ioeventfd;
1433+
1434+ if (copy_from_user(&ioeventfd, udata, sizeof(ioeventfd)))
1435+ return -EFAULT;
1436+
1437+ /* No other flags should be set */
1438+ if (ioeventfd.flags & ~PRIVCMD_IOEVENTFD_FLAG_DEASSIGN)
1439+ return -EINVAL;
1440+
1441+ /* If restriction is in place, check the domid matches */
1442+ if (data->domid != DOMID_INVALID && data->domid != ioeventfd.dom)
1443+ return -EPERM;
1444+
1445+ if (ioeventfd.flags & PRIVCMD_IOEVENTFD_FLAG_DEASSIGN)
1446+ return privcmd_ioeventfd_deassign(&ioeventfd);
1447+
1448+ return privcmd_ioeventfd_assign(&ioeventfd);
1449+}
1450+
1451+static void privcmd_ioeventfd_exit(void)
1452+{
1453+ struct privcmd_kernel_ioreq *kioreq, *tmp;
1454+ unsigned long flags;
1455+
1456+ mutex_lock(&ioreq_lock);
1457+ list_for_each_entry_safe(kioreq, tmp, &ioreq_list, list) {
1458+ struct privcmd_kernel_ioeventfd *kioeventfd, *tmp;
1459+
1460+ spin_lock_irqsave(&kioreq->lock, flags);
1461+ list_for_each_entry_safe(kioeventfd, tmp, &kioreq->ioeventfds, list)
1462+ ioeventfd_free(kioeventfd);
1463+ spin_unlock_irqrestore(&kioreq->lock, flags);
1464+
1465+ ioreq_free(kioreq);
1466+ }
1467+ mutex_unlock(&ioreq_lock);
1468+}
10821469 #else
10831470 static inline long privcmd_ioctl_irqfd(struct file *file, void __user *udata)
10841471 {
@@ -1093,7 +1480,16 @@ static inline int privcmd_irqfd_init(void) · 8 unmodified lines
10931480 static inline void privcmd_irqfd_exit(void)
10941481 {
10951482 }
1096−#endif /* CONFIG_XEN_PRIVCMD_IRQFD */
1483+
1484+static inline long privcmd_ioctl_ioeventfd(struct file *file, void __user *udata)
1485+{
1486+ return -EOPNOTSUPP;
1487+}
1488+
1489+static inline void privcmd_ioeventfd_exit(void)
1490+{
1491+}
1492+#endif /* CONFIG_XEN_PRIVCMD_EVENTFD */
10971493
10981494 static long privcmd_ioctl(struct file *file,
10991495 unsigned int cmd, unsigned long data)
@@ -1134,6 +1530,10 @@ static long privcmd_ioctl(struct file *file, · 34 unmodified lines
11341530 ret = privcmd_ioctl_irqfd(file, udata);
11351531 break;
11361532
1533+ case IOCTL_PRIVCMD_IOEVENTFD:
1534+ ret = privcmd_ioctl_ioeventfd(file, udata);
1535+ break;
1536+
11371537 default:
11381538 break;
11391539 }
@@ -1278,6 +1678,7 @@ err_privcmdbuf: · 138 unmodified lines
12781678
12791679 static void __exit privcmd_exit(void)
12801680 {
1681+ privcmd_ioeventfd_exit();
12811682 privcmd_irqfd_exit();
12821683 misc_deregister(&privcmd_dev);
12831684 misc_deregister(&xen_privcmdbuf_dev);
include/uapi/xen/privcmd.h+18−0
@@ -110,6 +110,22 @@ struct privcmd_irqfd { · 109 unmodified lines
110110 __u8 pad[2];
111111 };
112112
113+/* For privcmd_ioeventfd::flags */
114+#define PRIVCMD_IOEVENTFD_FLAG_DEASSIGN (1 << 0)
115+
116+struct privcmd_ioeventfd {
117+ __u64 ioreq;
118+ __u64 ports;
119+ __u64 addr;
120+ __u32 addr_len;
121+ __u32 event_fd;
122+ __u32 vcpus;
123+ __u32 vq;
124+ __u32 flags;
125+ domid_t dom;
126+ __u8 pad[2];
127+};
128+
113129 /*
114130 * @cmd: IOCTL_PRIVCMD_HYPERCALL
115131 * @arg: &privcmd_hypercall_t
@@ -139,5 +155,7 @@ struct privcmd_irqfd { · 23 unmodified lines
139155 _IOC(_IOC_NONE, 'P', 7, sizeof(struct privcmd_mmap_resource))
140156 #define IOCTL_PRIVCMD_IRQFD \
141157 _IOW('P', 8, struct privcmd_irqfd)
158+#define IOCTL_PRIVCMD_IOEVENTFD \
159+ _IOW('P', 9, struct privcmd_ioeventfd)
142160
143161 #endif /* __LINUX_PUBLIC_PRIVCMD_H__ */
include/xen/interface/hvm/ioreq.h+51−0
@@ -0,0 +1,51 @@
1+/* SPDX-License-Identifier: MIT */
2+/*
3+ * ioreq.h: I/O request definitions for device models
4+ * Copyright (c) 2004, Intel Corporation.
5+ */
6+
7+#ifndef __XEN_PUBLIC_HVM_IOREQ_H__
8+#define __XEN_PUBLIC_HVM_IOREQ_H__
9+
10+#define IOREQ_READ 1
11+#define IOREQ_WRITE 0
12+
13+#define STATE_IOREQ_NONE 0
14+#define STATE_IOREQ_READY 1
15+#define STATE_IOREQ_INPROCESS 2
16+#define STATE_IORESP_READY 3
17+
18+#define IOREQ_TYPE_PIO 0 /* pio */
19+#define IOREQ_TYPE_COPY 1 /* mmio ops */
20+#define IOREQ_TYPE_PCI_CONFIG 2
21+#define IOREQ_TYPE_TIMEOFFSET 7
22+#define IOREQ_TYPE_INVALIDATE 8 /* mapcache */
23+
24+/*
25+ * VMExit dispatcher should cooperate with instruction decoder to
26+ * prepare this structure and notify service OS and DM by sending
27+ * virq.
28+ *
29+ * For I/O type IOREQ_TYPE_PCI_CONFIG, the physical address is formatted
30+ * as follows:
31+ *
32+ * 63....48|47..40|39..35|34..32|31........0
33+ * SEGMENT |BUS |DEV |FN |OFFSET
34+ */
35+struct ioreq {
36+ uint64_t addr; /* physical address */
37+ uint64_t data; /* data (or paddr of data) */
38+ uint32_t count; /* for rep prefixes */
39+ uint32_t size; /* size in bytes */
40+ uint32_t vp_eport; /* evtchn for notifications to/from device model */
41+ uint16_t _pad0;
42+ uint8_t state:4;
43+ uint8_t data_is_ptr:1; /* if 1, data above is the guest paddr
44+ * of the real data to use. */
45+ uint8_t dir:1; /* 1=read, 0=write */
46+ uint8_t df:1;
47+ uint8_t _pad1:1;
48+ uint8_t type; /* I/O type */
49+};
50+
51+#endif /* __XEN_PUBLIC_HVM_IOREQ_H__ */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t