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
269 disaggregated Xen setups this driver might be needed for other269 disaggregated Xen setups this driver might be needed for other
270 domains, too.270 domains, too.
271 271
272config XEN_PRIVCMD_IRQFD272config XEN_PRIVCMD_EVENTFD
273 bool "Xen irqfd support"273 bool "Xen Ioeventfd and irqfd support"
274 depends on XEN_PRIVCMD && XEN_VIRTIO && EVENTFD274 depends on XEN_PRIVCMD && XEN_VIRTIO && EVENTFD
275 help275 help
276 Using the irqfd mechanism a virtio backend running in a daemon can276 Using the ioeventfd / irqfd mechanism a virtio backend running in a
277 speed up interrupt injection into a guest.277 daemon can speed up interrupt delivery from / to a guest.
278 278
279config XEN_ACPI_PROCESSOR279config XEN_ACPI_PROCESSOR
280 tristate "Xen ACPI processor"280 tristate "Xen ACPI processor"
drivers/xen/privcmd.c+403−2
@@ -29,15 +29,18 @@ · 28 unmodified lines
29#include <linux/seq_file.h>29#include <linux/seq_file.h>
30#include <linux/miscdevice.h>30#include <linux/miscdevice.h>
31#include <linux/moduleparam.h>31#include <linux/moduleparam.h>
32#include <linux/virtio_mmio.h>
32 33
33#include <asm/xen/hypervisor.h>34#include <asm/xen/hypervisor.h>
34#include <asm/xen/hypercall.h>35#include <asm/xen/hypercall.h>
35 36
36#include <xen/xen.h>37#include <xen/xen.h>
38#include <xen/events.h>
37#include <xen/privcmd.h>39#include <xen/privcmd.h>
38#include <xen/interface/xen.h>40#include <xen/interface/xen.h>
39#include <xen/interface/memory.h>41#include <xen/interface/memory.h>
40#include <xen/interface/hvm/dm_op.h>42#include <xen/interface/hvm/dm_op.h>
43#include <xen/interface/hvm/ioreq.h>
41#include <xen/features.h>44#include <xen/features.h>
42#include <xen/page.h>45#include <xen/page.h>
43#include <xen/xen-ops.h>46#include <xen/xen-ops.h>
@@ -782,6 +785,7 @@ static long privcmd_ioctl_mmap_resource(struct file *file, · 738 unmodified lines
782 goto out;785 goto out;
783 786
784 pages = vma->vm_private_data;787 pages = vma->vm_private_data;
788
785 for (i = 0; i < kdata.num; i++) {789 for (i = 0; i < kdata.num; i++) {
786 xen_pfn_t pfn =790 xen_pfn_t pfn =
787 page_to_xen_pfn(pages[i / XEN_PFN_PER_PAGE]);791 page_to_xen_pfn(pages[i / XEN_PFN_PER_PAGE]);
@@ -838,7 +842,7 @@ out: · 50 unmodified lines
838 return rc;842 return rc;
839}843}
840 844
841#ifdef CONFIG_XEN_PRIVCMD_IRQFD845#ifdef CONFIG_XEN_PRIVCMD_EVENTFD
842/* Irqfd support */846/* Irqfd support */
843static struct workqueue_struct *irqfd_cleanup_wq;847static struct workqueue_struct *irqfd_cleanup_wq;
844static DEFINE_MUTEX(irqfds_lock);848static DEFINE_MUTEX(irqfds_lock);
@@ -1079,6 +1083,389 @@ static void privcmd_irqfd_exit(void) · 234 unmodified lines
1079 1083
1080 destroy_workqueue(irqfd_cleanup_wq);1084 destroy_workqueue(irqfd_cleanup_wq);
1081}1085}
1086
1087/* Ioeventfd Support */
1088#define QUEUE_NOTIFY_VQ_MASK 0xFFFF
1089
1090static DEFINE_MUTEX(ioreq_lock);
1091static LIST_HEAD(ioreq_list);
1092
1093/* per-eventfd structure */
1094struct 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 */
1103struct ioreq_port {
1104 int vcpu;
1105 unsigned int port;
1106 struct privcmd_kernel_ioreq *kioreq;
1107};
1108
1109/* per-guest structure */
1110struct 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
1121static 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
1174static 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
1189static
1190struct 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
1256error_unbind:
1257 while (--i >= 0)
1258 unbind_from_irqhandler(irq_from_evtchn(ports[i]), &kioreq->ports[i]);
1259error_kfree_ports:
1260 kfree(ports);
1261error_kfree:
1262 kfree(kioreq);
1263 return ERR_PTR(ret);
1264}
1265
1266static struct privcmd_kernel_ioreq *
1267get_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
1306static 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
1313static 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
1372error_eventfd:
1373 eventfd_ctx_put(kioeventfd->eventfd);
1374
1375error_kfree:
1376 kfree(kioeventfd);
1377 return ret;
1378}
1379
1380static 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
1422unlock:
1423 mutex_unlock(&ioreq_lock);
1424 eventfd_ctx_put(eventfd);
1425
1426 return ret;
1427}
1428
1429static 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
1451static 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}
1082#else1469#else
1083static inline long privcmd_ioctl_irqfd(struct file *file, void __user *udata)1470static inline long privcmd_ioctl_irqfd(struct file *file, void __user *udata)
1084{1471{
@@ -1093,7 +1480,16 @@ static inline int privcmd_irqfd_init(void) · 8 unmodified lines
1093static inline void privcmd_irqfd_exit(void)1480static inline void privcmd_irqfd_exit(void)
1094{1481{
1095}1482}
1096#endif /* CONFIG_XEN_PRIVCMD_IRQFD */1483
1484static inline long privcmd_ioctl_ioeventfd(struct file *file, void __user *udata)
1485{
1486 return -EOPNOTSUPP;
1487}
1488
1489static inline void privcmd_ioeventfd_exit(void)
1490{
1491}
1492#endif /* CONFIG_XEN_PRIVCMD_EVENTFD */
1097 1493
1098static long privcmd_ioctl(struct file *file,1494static long privcmd_ioctl(struct file *file,
1099 unsigned int cmd, unsigned long data)1495 unsigned int cmd, unsigned long data)
@@ -1134,6 +1530,10 @@ static long privcmd_ioctl(struct file *file, · 34 unmodified lines
1134 ret = privcmd_ioctl_irqfd(file, udata);1530 ret = privcmd_ioctl_irqfd(file, udata);
1135 break;1531 break;
1136 1532
1533 case IOCTL_PRIVCMD_IOEVENTFD:
1534 ret = privcmd_ioctl_ioeventfd(file, udata);
1535 break;
1536
1137 default:1537 default:
1138 break;1538 break;
1139 }1539 }
@@ -1278,6 +1678,7 @@ err_privcmdbuf: · 138 unmodified lines
1278 1678
1279static void __exit privcmd_exit(void)1679static void __exit privcmd_exit(void)
1280{1680{
1681 privcmd_ioeventfd_exit();
1281 privcmd_irqfd_exit();1682 privcmd_irqfd_exit();
1282 misc_deregister(&privcmd_dev);1683 misc_deregister(&privcmd_dev);
1283 misc_deregister(&xen_privcmdbuf_dev);1684 misc_deregister(&xen_privcmdbuf_dev);
include/uapi/xen/privcmd.h+18−0
@@ -110,6 +110,22 @@ struct privcmd_irqfd { · 109 unmodified lines
110 __u8 pad[2];110 __u8 pad[2];
111};111};
112 112
113/* For privcmd_ioeventfd::flags */
114#define PRIVCMD_IOEVENTFD_FLAG_DEASSIGN (1 << 0)
115
116struct 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
113/*129/*
114 * @cmd: IOCTL_PRIVCMD_HYPERCALL130 * @cmd: IOCTL_PRIVCMD_HYPERCALL
115 * @arg: &privcmd_hypercall_t131 * @arg: &privcmd_hypercall_t
@@ -139,5 +155,7 @@ struct privcmd_irqfd { · 23 unmodified lines
139 _IOC(_IOC_NONE, 'P', 7, sizeof(struct privcmd_mmap_resource))155 _IOC(_IOC_NONE, 'P', 7, sizeof(struct privcmd_mmap_resource))
140#define IOCTL_PRIVCMD_IRQFD \156#define IOCTL_PRIVCMD_IRQFD \
141 _IOW('P', 8, struct privcmd_irqfd)157 _IOW('P', 8, struct privcmd_irqfd)
158#define IOCTL_PRIVCMD_IOEVENTFD \
159 _IOW('P', 9, struct privcmd_ioeventfd)
142 160
143#endif /* __LINUX_PUBLIC_PRIVCMD_H__ */161#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 */
35struct 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