2 * Copyright © 2018, 2021 Oracle and/or its affiliates.
4 * This work is licensed under the terms of the GNU GPL, version 2 or later.
5 * See the COPYING file in the top-level directory.
9 #include "qemu/osdep.h"
10 #include "qemu-common.h"
12 #include "hw/remote/proxy.h"
13 #include "hw/pci/pci.h"
14 #include "qapi/error.h"
15 #include "io/channel-util.h"
16 #include "hw/qdev-properties.h"
17 #include "monitor/monitor.h"
18 #include "migration/blocker.h"
19 #include "qemu/sockets.h"
20 #include "hw/remote/mpqemu-link.h"
21 #include "qemu/error-report.h"
22 #include "hw/remote/proxy-memory-listener.h"
23 #include "qom/object.h"
24 #include "qemu/event_notifier.h"
25 #include "sysemu/kvm.h"
26 #include "util/event_notifier-posix.c"
28 static void proxy_intx_update(PCIDevice
*pci_dev
)
30 PCIProxyDev
*dev
= PCI_PROXY_DEV(pci_dev
);
32 int pin
= pci_get_byte(pci_dev
->config
+ PCI_INTERRUPT_PIN
) - 1;
34 if (dev
->virq
!= -1) {
35 kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state
, &dev
->intr
, dev
->virq
);
39 route
= pci_device_route_intx_to_irq(pci_dev
, pin
);
41 dev
->virq
= route
.irq
;
43 if (dev
->virq
!= -1) {
44 kvm_irqchip_add_irqfd_notifier_gsi(kvm_state
, &dev
->intr
,
45 &dev
->resample
, dev
->virq
);
49 static void setup_irqfd(PCIProxyDev
*dev
)
51 PCIDevice
*pci_dev
= PCI_DEVICE(dev
);
53 Error
*local_err
= NULL
;
55 event_notifier_init(&dev
->intr
, 0);
56 event_notifier_init(&dev
->resample
, 0);
58 memset(&msg
, 0, sizeof(MPQemuMsg
));
59 msg
.cmd
= MPQEMU_CMD_SET_IRQFD
;
61 msg
.fds
[0] = event_notifier_get_fd(&dev
->intr
);
62 msg
.fds
[1] = event_notifier_get_fd(&dev
->resample
);
65 if (!mpqemu_msg_send(&msg
, dev
->ioc
, &local_err
)) {
66 error_report_err(local_err
);
71 proxy_intx_update(pci_dev
);
73 pci_device_set_intx_routing_notifier(pci_dev
, proxy_intx_update
);
76 static void pci_proxy_dev_realize(PCIDevice
*device
, Error
**errp
)
79 PCIProxyDev
*dev
= PCI_PROXY_DEV(device
);
83 error_setg(errp
, "fd parameter not specified for %s",
88 fd
= monitor_fd_param(monitor_cur(), dev
->fd
, errp
);
90 error_prepend(errp
, "proxy: unable to parse fd %s: ", dev
->fd
);
94 if (!fd_is_socket(fd
)) {
95 error_setg(errp
, "proxy: fd %d is not a socket", fd
);
100 dev
->ioc
= qio_channel_new_fd(fd
, errp
);
102 error_setg(&dev
->migration_blocker
, "%s does not support migration",
104 migrate_add_blocker(dev
->migration_blocker
, errp
);
106 qemu_mutex_init(&dev
->io_mutex
);
107 qio_channel_set_blocking(dev
->ioc
, true, NULL
);
109 proxy_memory_listener_configure(&dev
->proxy_listener
, dev
->ioc
);
114 static void pci_proxy_dev_exit(PCIDevice
*pdev
)
116 PCIProxyDev
*dev
= PCI_PROXY_DEV(pdev
);
119 qio_channel_close(dev
->ioc
, NULL
);
122 migrate_del_blocker(dev
->migration_blocker
);
124 error_free(dev
->migration_blocker
);
126 proxy_memory_listener_deconfigure(&dev
->proxy_listener
);
128 event_notifier_cleanup(&dev
->intr
);
129 event_notifier_cleanup(&dev
->resample
);
132 static void config_op_send(PCIProxyDev
*pdev
, uint32_t addr
, uint32_t *val
,
133 int len
, unsigned int op
)
135 MPQemuMsg msg
= { 0 };
136 uint64_t ret
= -EINVAL
;
137 Error
*local_err
= NULL
;
140 msg
.data
.pci_conf_data
.addr
= addr
;
141 msg
.data
.pci_conf_data
.val
= (op
== MPQEMU_CMD_PCI_CFGWRITE
) ? *val
: 0;
142 msg
.data
.pci_conf_data
.len
= len
;
143 msg
.size
= sizeof(PciConfDataMsg
);
145 ret
= mpqemu_msg_send_and_await_reply(&msg
, pdev
, &local_err
);
147 error_report_err(local_err
);
150 if (ret
== UINT64_MAX
) {
151 error_report("Failed to perform PCI config %s operation",
152 (op
== MPQEMU_CMD_PCI_CFGREAD
) ? "READ" : "WRITE");
155 if (op
== MPQEMU_CMD_PCI_CFGREAD
) {
156 *val
= (uint32_t)ret
;
160 static uint32_t pci_proxy_read_config(PCIDevice
*d
, uint32_t addr
, int len
)
164 config_op_send(PCI_PROXY_DEV(d
), addr
, &val
, len
, MPQEMU_CMD_PCI_CFGREAD
);
169 static void pci_proxy_write_config(PCIDevice
*d
, uint32_t addr
, uint32_t val
,
173 * Some of the functions access the copy of remote device's PCI config
174 * space which is cached in the proxy device. Therefore, maintain
177 pci_default_write_config(d
, addr
, val
, len
);
179 config_op_send(PCI_PROXY_DEV(d
), addr
, &val
, len
, MPQEMU_CMD_PCI_CFGWRITE
);
182 static Property proxy_properties
[] = {
183 DEFINE_PROP_STRING("fd", PCIProxyDev
, fd
),
184 DEFINE_PROP_END_OF_LIST(),
187 static void pci_proxy_dev_class_init(ObjectClass
*klass
, void *data
)
189 DeviceClass
*dc
= DEVICE_CLASS(klass
);
190 PCIDeviceClass
*k
= PCI_DEVICE_CLASS(klass
);
192 k
->realize
= pci_proxy_dev_realize
;
193 k
->exit
= pci_proxy_dev_exit
;
194 k
->config_read
= pci_proxy_read_config
;
195 k
->config_write
= pci_proxy_write_config
;
197 device_class_set_props(dc
, proxy_properties
);
200 static const TypeInfo pci_proxy_dev_type_info
= {
201 .name
= TYPE_PCI_PROXY_DEV
,
202 .parent
= TYPE_PCI_DEVICE
,
203 .instance_size
= sizeof(PCIProxyDev
),
204 .class_init
= pci_proxy_dev_class_init
,
205 .interfaces
= (InterfaceInfo
[]) {
206 { INTERFACE_CONVENTIONAL_PCI_DEVICE
},
211 static void pci_proxy_dev_register_types(void)
213 type_register_static(&pci_proxy_dev_type_info
);
216 type_init(pci_proxy_dev_register_types
)
218 static void send_bar_access_msg(PCIProxyDev
*pdev
, MemoryRegion
*mr
,
219 bool write
, hwaddr addr
, uint64_t *val
,
220 unsigned size
, bool memory
)
222 MPQemuMsg msg
= { 0 };
224 Error
*local_err
= NULL
;
226 msg
.size
= sizeof(BarAccessMsg
);
227 msg
.data
.bar_access
.addr
= mr
->addr
+ addr
;
228 msg
.data
.bar_access
.size
= size
;
229 msg
.data
.bar_access
.memory
= memory
;
232 msg
.cmd
= MPQEMU_CMD_BAR_WRITE
;
233 msg
.data
.bar_access
.val
= *val
;
235 msg
.cmd
= MPQEMU_CMD_BAR_READ
;
238 ret
= mpqemu_msg_send_and_await_reply(&msg
, pdev
, &local_err
);
240 error_report_err(local_err
);
248 static void proxy_bar_write(void *opaque
, hwaddr addr
, uint64_t val
,
251 ProxyMemoryRegion
*pmr
= opaque
;
253 send_bar_access_msg(pmr
->dev
, &pmr
->mr
, true, addr
, &val
, size
,
257 static uint64_t proxy_bar_read(void *opaque
, hwaddr addr
, unsigned size
)
259 ProxyMemoryRegion
*pmr
= opaque
;
262 send_bar_access_msg(pmr
->dev
, &pmr
->mr
, false, addr
, &val
, size
,
268 const MemoryRegionOps proxy_mr_ops
= {
269 .read
= proxy_bar_read
,
270 .write
= proxy_bar_write
,
271 .endianness
= DEVICE_NATIVE_ENDIAN
,
273 .min_access_size
= 1,
274 .max_access_size
= 8,