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"
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
);
30 void coroutine_fn
mpqemu_remote_msg_loop_co(void *data
)
32 g_autofree RemoteCommDev
*com
= (RemoteCommDev
*)data
;
33 PCIDevice
*pci_dev
= NULL
;
34 Error
*local_err
= NULL
;
42 if (!mpqemu_msg_recv(&msg
, com
->ioc
, &local_err
)) {
46 if (!mpqemu_msg_valid(&msg
)) {
47 error_setg(&local_err
, "Received invalid message from proxy"
48 "in remote process pid="FMT_pid
"",
54 case MPQEMU_CMD_PCI_CFGWRITE
:
55 process_config_write(com
->ioc
, pci_dev
, &msg
, &local_err
);
57 case MPQEMU_CMD_PCI_CFGREAD
:
58 process_config_read(com
->ioc
, pci_dev
, &msg
, &local_err
);
60 case MPQEMU_CMD_BAR_WRITE
:
61 process_bar_write(com
->ioc
, &msg
, &local_err
);
63 case MPQEMU_CMD_BAR_READ
:
64 process_bar_read(com
->ioc
, &msg
, &local_err
);
66 case MPQEMU_CMD_SYNC_SYSMEM
:
67 remote_sysmem_reconfig(&msg
, &local_err
);
69 case MPQEMU_CMD_SET_IRQFD
:
70 process_set_irqfd_msg(pci_dev
, &msg
);
73 error_setg(&local_err
,
74 "Unknown command (%d) received for device %s"
76 msg
.cmd
, DEVICE(pci_dev
)->id
, getpid());
81 error_report_err(local_err
);
82 qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_ERROR
);
84 qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN
);
88 static void process_config_write(QIOChannel
*ioc
, PCIDevice
*dev
,
89 MPQemuMsg
*msg
, Error
**errp
)
92 PciConfDataMsg
*conf
= (PciConfDataMsg
*)&msg
->data
.pci_conf_data
;
93 MPQemuMsg ret
= { 0 };
95 if ((conf
->addr
+ sizeof(conf
->val
)) > pci_config_size(dev
)) {
96 error_setg(errp
, "Bad address for PCI config write, pid "FMT_pid
".",
98 ret
.data
.u64
= UINT64_MAX
;
100 pci_default_write_config(dev
, conf
->addr
, conf
->val
, conf
->len
);
103 ret
.cmd
= MPQEMU_CMD_RET
;
104 ret
.size
= sizeof(ret
.data
.u64
);
106 if (!mpqemu_msg_send(&ret
, ioc
, NULL
)) {
107 error_prepend(errp
, "Error returning code to proxy, pid "FMT_pid
": ",
112 static void process_config_read(QIOChannel
*ioc
, PCIDevice
*dev
,
113 MPQemuMsg
*msg
, Error
**errp
)
116 PciConfDataMsg
*conf
= (PciConfDataMsg
*)&msg
->data
.pci_conf_data
;
117 MPQemuMsg ret
= { 0 };
119 if ((conf
->addr
+ sizeof(conf
->val
)) > pci_config_size(dev
)) {
120 error_setg(errp
, "Bad address for PCI config read, pid "FMT_pid
".",
122 ret
.data
.u64
= UINT64_MAX
;
124 ret
.data
.u64
= pci_default_read_config(dev
, conf
->addr
, conf
->len
);
127 ret
.cmd
= MPQEMU_CMD_RET
;
128 ret
.size
= sizeof(ret
.data
.u64
);
130 if (!mpqemu_msg_send(&ret
, ioc
, NULL
)) {
131 error_prepend(errp
, "Error returning code to proxy, pid "FMT_pid
": ",
136 static void process_bar_write(QIOChannel
*ioc
, MPQemuMsg
*msg
, Error
**errp
)
139 BarAccessMsg
*bar_access
= &msg
->data
.bar_access
;
141 bar_access
->memory
? &address_space_memory
: &address_space_io
;
142 MPQemuMsg ret
= { 0 };
146 if (!is_power_of_2(bar_access
->size
) ||
147 (bar_access
->size
> sizeof(uint64_t))) {
148 ret
.data
.u64
= UINT64_MAX
;
152 val
= cpu_to_le64(bar_access
->val
);
154 res
= address_space_rw(as
, bar_access
->addr
, MEMTXATTRS_UNSPECIFIED
,
155 (void *)&val
, bar_access
->size
, true);
157 if (res
!= MEMTX_OK
) {
158 error_setg(errp
, "Bad address %"PRIx64
" for mem write, pid "FMT_pid
".",
159 bar_access
->addr
, getpid());
164 ret
.cmd
= MPQEMU_CMD_RET
;
165 ret
.size
= sizeof(ret
.data
.u64
);
167 if (!mpqemu_msg_send(&ret
, ioc
, NULL
)) {
168 error_prepend(errp
, "Error returning code to proxy, pid "FMT_pid
": ",
173 static void process_bar_read(QIOChannel
*ioc
, MPQemuMsg
*msg
, Error
**errp
)
176 BarAccessMsg
*bar_access
= &msg
->data
.bar_access
;
177 MPQemuMsg ret
= { 0 };
182 as
= bar_access
->memory
? &address_space_memory
: &address_space_io
;
184 if (!is_power_of_2(bar_access
->size
) ||
185 (bar_access
->size
> sizeof(uint64_t))) {
190 res
= address_space_rw(as
, bar_access
->addr
, MEMTXATTRS_UNSPECIFIED
,
191 (void *)&val
, bar_access
->size
, false);
193 if (res
!= MEMTX_OK
) {
194 error_setg(errp
, "Bad address %"PRIx64
" for mem read, pid "FMT_pid
".",
195 bar_access
->addr
, getpid());
200 ret
.cmd
= MPQEMU_CMD_RET
;
201 ret
.data
.u64
= le64_to_cpu(val
);
202 ret
.size
= sizeof(ret
.data
.u64
);
204 if (!mpqemu_msg_send(&ret
, ioc
, NULL
)) {
205 error_prepend(errp
, "Error returning code to proxy, pid "FMT_pid
": ",