2 * Copyright © 2020, 2021 Oracle and/or its affiliates.
4 * This work is licensed under the terms of the GNU GPL-v2, version 2 or later.
6 * See the COPYING file in the top-level directory.
10 #include "qemu/osdep.h"
11 #include "qemu-common.h"
13 #include "hw/remote/machine.h"
14 #include "io/channel.h"
15 #include "hw/remote/mpqemu-link.h"
16 #include "qapi/error.h"
17 #include "sysemu/runstate.h"
18 #include "hw/pci/pci.h"
19 #include "exec/memattrs.h"
20 #include "hw/remote/memory.h"
21 #include "hw/remote/iohub.h"
22 #include "sysemu/reset.h"
24 static void process_config_write(QIOChannel
*ioc
, PCIDevice
*dev
,
25 MPQemuMsg
*msg
, Error
**errp
);
26 static void process_config_read(QIOChannel
*ioc
, PCIDevice
*dev
,
27 MPQemuMsg
*msg
, Error
**errp
);
28 static void process_bar_write(QIOChannel
*ioc
, MPQemuMsg
*msg
, Error
**errp
);
29 static void process_bar_read(QIOChannel
*ioc
, MPQemuMsg
*msg
, Error
**errp
);
30 static void process_device_reset_msg(QIOChannel
*ioc
, PCIDevice
*dev
,
33 void coroutine_fn
mpqemu_remote_msg_loop_co(void *data
)
35 g_autofree RemoteCommDev
*com
= (RemoteCommDev
*)data
;
36 PCIDevice
*pci_dev
= NULL
;
37 Error
*local_err
= NULL
;
45 if (!mpqemu_msg_recv(&msg
, com
->ioc
, &local_err
)) {
49 if (!mpqemu_msg_valid(&msg
)) {
50 error_setg(&local_err
, "Received invalid message from proxy"
51 "in remote process pid="FMT_pid
"",
57 case MPQEMU_CMD_PCI_CFGWRITE
:
58 process_config_write(com
->ioc
, pci_dev
, &msg
, &local_err
);
60 case MPQEMU_CMD_PCI_CFGREAD
:
61 process_config_read(com
->ioc
, pci_dev
, &msg
, &local_err
);
63 case MPQEMU_CMD_BAR_WRITE
:
64 process_bar_write(com
->ioc
, &msg
, &local_err
);
66 case MPQEMU_CMD_BAR_READ
:
67 process_bar_read(com
->ioc
, &msg
, &local_err
);
69 case MPQEMU_CMD_SYNC_SYSMEM
:
70 remote_sysmem_reconfig(&msg
, &local_err
);
72 case MPQEMU_CMD_SET_IRQFD
:
73 process_set_irqfd_msg(pci_dev
, &msg
);
75 case MPQEMU_CMD_DEVICE_RESET
:
76 process_device_reset_msg(com
->ioc
, pci_dev
, &local_err
);
79 error_setg(&local_err
,
80 "Unknown command (%d) received for device %s"
82 msg
.cmd
, DEVICE(pci_dev
)->id
, getpid());
87 error_report_err(local_err
);
88 qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_ERROR
);
90 qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN
);
94 static void process_config_write(QIOChannel
*ioc
, PCIDevice
*dev
,
95 MPQemuMsg
*msg
, Error
**errp
)
98 PciConfDataMsg
*conf
= (PciConfDataMsg
*)&msg
->data
.pci_conf_data
;
99 MPQemuMsg ret
= { 0 };
101 if ((conf
->addr
+ sizeof(conf
->val
)) > pci_config_size(dev
)) {
102 error_setg(errp
, "Bad address for PCI config write, pid "FMT_pid
".",
104 ret
.data
.u64
= UINT64_MAX
;
106 pci_default_write_config(dev
, conf
->addr
, conf
->val
, conf
->len
);
109 ret
.cmd
= MPQEMU_CMD_RET
;
110 ret
.size
= sizeof(ret
.data
.u64
);
112 if (!mpqemu_msg_send(&ret
, ioc
, NULL
)) {
113 error_prepend(errp
, "Error returning code to proxy, pid "FMT_pid
": ",
118 static void process_config_read(QIOChannel
*ioc
, PCIDevice
*dev
,
119 MPQemuMsg
*msg
, Error
**errp
)
122 PciConfDataMsg
*conf
= (PciConfDataMsg
*)&msg
->data
.pci_conf_data
;
123 MPQemuMsg ret
= { 0 };
125 if ((conf
->addr
+ sizeof(conf
->val
)) > pci_config_size(dev
)) {
126 error_setg(errp
, "Bad address for PCI config read, pid "FMT_pid
".",
128 ret
.data
.u64
= UINT64_MAX
;
130 ret
.data
.u64
= pci_default_read_config(dev
, conf
->addr
, conf
->len
);
133 ret
.cmd
= MPQEMU_CMD_RET
;
134 ret
.size
= sizeof(ret
.data
.u64
);
136 if (!mpqemu_msg_send(&ret
, ioc
, NULL
)) {
137 error_prepend(errp
, "Error returning code to proxy, pid "FMT_pid
": ",
142 static void process_bar_write(QIOChannel
*ioc
, MPQemuMsg
*msg
, Error
**errp
)
145 BarAccessMsg
*bar_access
= &msg
->data
.bar_access
;
147 bar_access
->memory
? &address_space_memory
: &address_space_io
;
148 MPQemuMsg ret
= { 0 };
152 if (!is_power_of_2(bar_access
->size
) ||
153 (bar_access
->size
> sizeof(uint64_t))) {
154 ret
.data
.u64
= UINT64_MAX
;
158 val
= cpu_to_le64(bar_access
->val
);
160 res
= address_space_rw(as
, bar_access
->addr
, MEMTXATTRS_UNSPECIFIED
,
161 (void *)&val
, bar_access
->size
, true);
163 if (res
!= MEMTX_OK
) {
164 error_setg(errp
, "Bad address %"PRIx64
" for mem write, pid "FMT_pid
".",
165 bar_access
->addr
, getpid());
170 ret
.cmd
= MPQEMU_CMD_RET
;
171 ret
.size
= sizeof(ret
.data
.u64
);
173 if (!mpqemu_msg_send(&ret
, ioc
, NULL
)) {
174 error_prepend(errp
, "Error returning code to proxy, pid "FMT_pid
": ",
179 static void process_bar_read(QIOChannel
*ioc
, MPQemuMsg
*msg
, Error
**errp
)
182 BarAccessMsg
*bar_access
= &msg
->data
.bar_access
;
183 MPQemuMsg ret
= { 0 };
188 as
= bar_access
->memory
? &address_space_memory
: &address_space_io
;
190 if (!is_power_of_2(bar_access
->size
) ||
191 (bar_access
->size
> sizeof(uint64_t))) {
196 res
= address_space_rw(as
, bar_access
->addr
, MEMTXATTRS_UNSPECIFIED
,
197 (void *)&val
, bar_access
->size
, false);
199 if (res
!= MEMTX_OK
) {
200 error_setg(errp
, "Bad address %"PRIx64
" for mem read, pid "FMT_pid
".",
201 bar_access
->addr
, getpid());
206 ret
.cmd
= MPQEMU_CMD_RET
;
207 ret
.data
.u64
= le64_to_cpu(val
);
208 ret
.size
= sizeof(ret
.data
.u64
);
210 if (!mpqemu_msg_send(&ret
, ioc
, NULL
)) {
211 error_prepend(errp
, "Error returning code to proxy, pid "FMT_pid
": ",
216 static void process_device_reset_msg(QIOChannel
*ioc
, PCIDevice
*dev
,
219 DeviceClass
*dc
= DEVICE_GET_CLASS(dev
);
220 DeviceState
*s
= DEVICE(dev
);
221 MPQemuMsg ret
= { 0 };
227 ret
.cmd
= MPQEMU_CMD_RET
;
229 mpqemu_msg_send(&ret
, ioc
, errp
);