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"
12 #include "hw/remote/machine.h"
13 #include "io/channel.h"
14 #include "hw/remote/mpqemu-link.h"
15 #include "qapi/error.h"
16 #include "sysemu/runstate.h"
17 #include "hw/pci/pci.h"
18 #include "exec/memattrs.h"
19 #include "hw/remote/memory.h"
20 #include "hw/remote/iohub.h"
21 #include "sysemu/reset.h"
23 static void process_config_write(QIOChannel
*ioc
, PCIDevice
*dev
,
24 MPQemuMsg
*msg
, Error
**errp
);
25 static void process_config_read(QIOChannel
*ioc
, PCIDevice
*dev
,
26 MPQemuMsg
*msg
, Error
**errp
);
27 static void process_bar_write(QIOChannel
*ioc
, MPQemuMsg
*msg
, Error
**errp
);
28 static void process_bar_read(QIOChannel
*ioc
, MPQemuMsg
*msg
, Error
**errp
);
29 static void process_device_reset_msg(QIOChannel
*ioc
, PCIDevice
*dev
,
32 void coroutine_fn
mpqemu_remote_msg_loop_co(void *data
)
34 g_autofree RemoteCommDev
*com
= (RemoteCommDev
*)data
;
35 PCIDevice
*pci_dev
= NULL
;
36 Error
*local_err
= NULL
;
44 if (!mpqemu_msg_recv(&msg
, com
->ioc
, &local_err
)) {
48 if (!mpqemu_msg_valid(&msg
)) {
49 error_setg(&local_err
, "Received invalid message from proxy"
50 "in remote process pid="FMT_pid
"",
56 case MPQEMU_CMD_PCI_CFGWRITE
:
57 process_config_write(com
->ioc
, pci_dev
, &msg
, &local_err
);
59 case MPQEMU_CMD_PCI_CFGREAD
:
60 process_config_read(com
->ioc
, pci_dev
, &msg
, &local_err
);
62 case MPQEMU_CMD_BAR_WRITE
:
63 process_bar_write(com
->ioc
, &msg
, &local_err
);
65 case MPQEMU_CMD_BAR_READ
:
66 process_bar_read(com
->ioc
, &msg
, &local_err
);
68 case MPQEMU_CMD_SYNC_SYSMEM
:
69 remote_sysmem_reconfig(&msg
, &local_err
);
71 case MPQEMU_CMD_SET_IRQFD
:
72 process_set_irqfd_msg(pci_dev
, &msg
);
74 case MPQEMU_CMD_DEVICE_RESET
:
75 process_device_reset_msg(com
->ioc
, pci_dev
, &local_err
);
78 error_setg(&local_err
,
79 "Unknown command (%d) received for device %s"
81 msg
.cmd
, DEVICE(pci_dev
)->id
, getpid());
86 error_report_err(local_err
);
87 qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_ERROR
);
89 qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN
);
93 static void process_config_write(QIOChannel
*ioc
, PCIDevice
*dev
,
94 MPQemuMsg
*msg
, Error
**errp
)
97 PciConfDataMsg
*conf
= (PciConfDataMsg
*)&msg
->data
.pci_conf_data
;
98 MPQemuMsg ret
= { 0 };
100 if ((conf
->addr
+ sizeof(conf
->val
)) > pci_config_size(dev
)) {
101 error_setg(errp
, "Bad address for PCI config write, pid "FMT_pid
".",
103 ret
.data
.u64
= UINT64_MAX
;
105 pci_default_write_config(dev
, conf
->addr
, conf
->val
, conf
->len
);
108 ret
.cmd
= MPQEMU_CMD_RET
;
109 ret
.size
= sizeof(ret
.data
.u64
);
111 if (!mpqemu_msg_send(&ret
, ioc
, NULL
)) {
112 error_prepend(errp
, "Error returning code to proxy, pid "FMT_pid
": ",
117 static void process_config_read(QIOChannel
*ioc
, PCIDevice
*dev
,
118 MPQemuMsg
*msg
, Error
**errp
)
121 PciConfDataMsg
*conf
= (PciConfDataMsg
*)&msg
->data
.pci_conf_data
;
122 MPQemuMsg ret
= { 0 };
124 if ((conf
->addr
+ sizeof(conf
->val
)) > pci_config_size(dev
)) {
125 error_setg(errp
, "Bad address for PCI config read, pid "FMT_pid
".",
127 ret
.data
.u64
= UINT64_MAX
;
129 ret
.data
.u64
= pci_default_read_config(dev
, conf
->addr
, conf
->len
);
132 ret
.cmd
= MPQEMU_CMD_RET
;
133 ret
.size
= sizeof(ret
.data
.u64
);
135 if (!mpqemu_msg_send(&ret
, ioc
, NULL
)) {
136 error_prepend(errp
, "Error returning code to proxy, pid "FMT_pid
": ",
141 static void process_bar_write(QIOChannel
*ioc
, MPQemuMsg
*msg
, Error
**errp
)
144 BarAccessMsg
*bar_access
= &msg
->data
.bar_access
;
146 bar_access
->memory
? &address_space_memory
: &address_space_io
;
147 MPQemuMsg ret
= { 0 };
151 if (!is_power_of_2(bar_access
->size
) ||
152 (bar_access
->size
> sizeof(uint64_t))) {
153 ret
.data
.u64
= UINT64_MAX
;
157 val
= cpu_to_le64(bar_access
->val
);
159 res
= address_space_rw(as
, bar_access
->addr
, MEMTXATTRS_UNSPECIFIED
,
160 (void *)&val
, bar_access
->size
, true);
162 if (res
!= MEMTX_OK
) {
163 error_setg(errp
, "Bad address %"PRIx64
" for mem write, pid "FMT_pid
".",
164 bar_access
->addr
, getpid());
169 ret
.cmd
= MPQEMU_CMD_RET
;
170 ret
.size
= sizeof(ret
.data
.u64
);
172 if (!mpqemu_msg_send(&ret
, ioc
, NULL
)) {
173 error_prepend(errp
, "Error returning code to proxy, pid "FMT_pid
": ",
178 static void process_bar_read(QIOChannel
*ioc
, MPQemuMsg
*msg
, Error
**errp
)
181 BarAccessMsg
*bar_access
= &msg
->data
.bar_access
;
182 MPQemuMsg ret
= { 0 };
187 as
= bar_access
->memory
? &address_space_memory
: &address_space_io
;
189 if (!is_power_of_2(bar_access
->size
) ||
190 (bar_access
->size
> sizeof(uint64_t))) {
195 res
= address_space_rw(as
, bar_access
->addr
, MEMTXATTRS_UNSPECIFIED
,
196 (void *)&val
, bar_access
->size
, false);
198 if (res
!= MEMTX_OK
) {
199 error_setg(errp
, "Bad address %"PRIx64
" for mem read, pid "FMT_pid
".",
200 bar_access
->addr
, getpid());
205 ret
.cmd
= MPQEMU_CMD_RET
;
206 ret
.data
.u64
= le64_to_cpu(val
);
207 ret
.size
= sizeof(ret
.data
.u64
);
209 if (!mpqemu_msg_send(&ret
, ioc
, NULL
)) {
210 error_prepend(errp
, "Error returning code to proxy, pid "FMT_pid
": ",
215 static void process_device_reset_msg(QIOChannel
*ioc
, PCIDevice
*dev
,
218 DeviceClass
*dc
= DEVICE_GET_CLASS(dev
);
219 DeviceState
*s
= DEVICE(dev
);
220 MPQemuMsg ret
= { 0 };
226 ret
.cmd
= MPQEMU_CMD_RET
;
228 mpqemu_msg_send(&ret
, ioc
, errp
);