2
0

message.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*
  2. * Copyright © 2020, 2021 Oracle and/or its affiliates.
  3. *
  4. * This work is licensed under the terms of the GNU GPL-v2, version 2 or later.
  5. *
  6. * See the COPYING file in the top-level directory.
  7. *
  8. */
  9. #include "qemu/osdep.h"
  10. #include "hw/remote/machine.h"
  11. #include "io/channel.h"
  12. #include "hw/remote/mpqemu-link.h"
  13. #include "qapi/error.h"
  14. #include "sysemu/runstate.h"
  15. #include "hw/pci/pci.h"
  16. #include "exec/memattrs.h"
  17. #include "hw/remote/memory.h"
  18. #include "hw/remote/iohub.h"
  19. #include "sysemu/reset.h"
  20. static void process_config_write(QIOChannel *ioc, PCIDevice *dev,
  21. MPQemuMsg *msg, Error **errp);
  22. static void process_config_read(QIOChannel *ioc, PCIDevice *dev,
  23. MPQemuMsg *msg, Error **errp);
  24. static void process_bar_write(QIOChannel *ioc, MPQemuMsg *msg, Error **errp);
  25. static void process_bar_read(QIOChannel *ioc, MPQemuMsg *msg, Error **errp);
  26. static void process_device_reset_msg(QIOChannel *ioc, PCIDevice *dev,
  27. Error **errp);
  28. void coroutine_fn mpqemu_remote_msg_loop_co(void *data)
  29. {
  30. g_autofree RemoteCommDev *com = (RemoteCommDev *)data;
  31. PCIDevice *pci_dev = NULL;
  32. Error *local_err = NULL;
  33. assert(com->ioc);
  34. pci_dev = com->dev;
  35. for (; !local_err;) {
  36. MPQemuMsg msg = {0};
  37. if (!mpqemu_msg_recv(&msg, com->ioc, &local_err)) {
  38. break;
  39. }
  40. if (!mpqemu_msg_valid(&msg)) {
  41. error_setg(&local_err, "Received invalid message from proxy"
  42. "in remote process pid="FMT_pid"",
  43. getpid());
  44. break;
  45. }
  46. switch (msg.cmd) {
  47. case MPQEMU_CMD_PCI_CFGWRITE:
  48. process_config_write(com->ioc, pci_dev, &msg, &local_err);
  49. break;
  50. case MPQEMU_CMD_PCI_CFGREAD:
  51. process_config_read(com->ioc, pci_dev, &msg, &local_err);
  52. break;
  53. case MPQEMU_CMD_BAR_WRITE:
  54. process_bar_write(com->ioc, &msg, &local_err);
  55. break;
  56. case MPQEMU_CMD_BAR_READ:
  57. process_bar_read(com->ioc, &msg, &local_err);
  58. break;
  59. case MPQEMU_CMD_SYNC_SYSMEM:
  60. remote_sysmem_reconfig(&msg, &local_err);
  61. break;
  62. case MPQEMU_CMD_SET_IRQFD:
  63. process_set_irqfd_msg(pci_dev, &msg);
  64. break;
  65. case MPQEMU_CMD_DEVICE_RESET:
  66. process_device_reset_msg(com->ioc, pci_dev, &local_err);
  67. break;
  68. default:
  69. error_setg(&local_err,
  70. "Unknown command (%d) received for device %s"
  71. " (pid="FMT_pid")",
  72. msg.cmd, DEVICE(pci_dev)->id, getpid());
  73. }
  74. }
  75. if (local_err) {
  76. error_report_err(local_err);
  77. qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_ERROR);
  78. } else {
  79. qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
  80. }
  81. }
  82. static void process_config_write(QIOChannel *ioc, PCIDevice *dev,
  83. MPQemuMsg *msg, Error **errp)
  84. {
  85. ERRP_GUARD();
  86. PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data;
  87. MPQemuMsg ret = { 0 };
  88. if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) {
  89. error_setg(errp, "Bad address for PCI config write, pid "FMT_pid".",
  90. getpid());
  91. ret.data.u64 = UINT64_MAX;
  92. } else {
  93. pci_default_write_config(dev, conf->addr, conf->val, conf->len);
  94. }
  95. ret.cmd = MPQEMU_CMD_RET;
  96. ret.size = sizeof(ret.data.u64);
  97. if (!mpqemu_msg_send(&ret, ioc, NULL)) {
  98. error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
  99. getpid());
  100. }
  101. }
  102. static void process_config_read(QIOChannel *ioc, PCIDevice *dev,
  103. MPQemuMsg *msg, Error **errp)
  104. {
  105. ERRP_GUARD();
  106. PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data;
  107. MPQemuMsg ret = { 0 };
  108. if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) {
  109. error_setg(errp, "Bad address for PCI config read, pid "FMT_pid".",
  110. getpid());
  111. ret.data.u64 = UINT64_MAX;
  112. } else {
  113. ret.data.u64 = pci_default_read_config(dev, conf->addr, conf->len);
  114. }
  115. ret.cmd = MPQEMU_CMD_RET;
  116. ret.size = sizeof(ret.data.u64);
  117. if (!mpqemu_msg_send(&ret, ioc, NULL)) {
  118. error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
  119. getpid());
  120. }
  121. }
  122. static void process_bar_write(QIOChannel *ioc, MPQemuMsg *msg, Error **errp)
  123. {
  124. ERRP_GUARD();
  125. BarAccessMsg *bar_access = &msg->data.bar_access;
  126. AddressSpace *as =
  127. bar_access->memory ? &address_space_memory : &address_space_io;
  128. MPQemuMsg ret = { 0 };
  129. MemTxResult res;
  130. uint64_t val;
  131. if (!is_power_of_2(bar_access->size) ||
  132. (bar_access->size > sizeof(uint64_t))) {
  133. ret.data.u64 = UINT64_MAX;
  134. goto fail;
  135. }
  136. val = cpu_to_le64(bar_access->val);
  137. res = address_space_rw(as, bar_access->addr, MEMTXATTRS_UNSPECIFIED,
  138. (void *)&val, bar_access->size, true);
  139. if (res != MEMTX_OK) {
  140. error_setg(errp, "Bad address %"PRIx64" for mem write, pid "FMT_pid".",
  141. bar_access->addr, getpid());
  142. ret.data.u64 = -1;
  143. }
  144. fail:
  145. ret.cmd = MPQEMU_CMD_RET;
  146. ret.size = sizeof(ret.data.u64);
  147. if (!mpqemu_msg_send(&ret, ioc, NULL)) {
  148. error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
  149. getpid());
  150. }
  151. }
  152. static void process_bar_read(QIOChannel *ioc, MPQemuMsg *msg, Error **errp)
  153. {
  154. ERRP_GUARD();
  155. BarAccessMsg *bar_access = &msg->data.bar_access;
  156. MPQemuMsg ret = { 0 };
  157. AddressSpace *as;
  158. MemTxResult res;
  159. uint64_t val = 0;
  160. as = bar_access->memory ? &address_space_memory : &address_space_io;
  161. if (!is_power_of_2(bar_access->size) ||
  162. (bar_access->size > sizeof(uint64_t))) {
  163. val = UINT64_MAX;
  164. goto fail;
  165. }
  166. res = address_space_rw(as, bar_access->addr, MEMTXATTRS_UNSPECIFIED,
  167. (void *)&val, bar_access->size, false);
  168. if (res != MEMTX_OK) {
  169. error_setg(errp, "Bad address %"PRIx64" for mem read, pid "FMT_pid".",
  170. bar_access->addr, getpid());
  171. val = UINT64_MAX;
  172. }
  173. fail:
  174. ret.cmd = MPQEMU_CMD_RET;
  175. ret.data.u64 = le64_to_cpu(val);
  176. ret.size = sizeof(ret.data.u64);
  177. if (!mpqemu_msg_send(&ret, ioc, NULL)) {
  178. error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
  179. getpid());
  180. }
  181. }
  182. static void process_device_reset_msg(QIOChannel *ioc, PCIDevice *dev,
  183. Error **errp)
  184. {
  185. DeviceClass *dc = DEVICE_GET_CLASS(dev);
  186. DeviceState *s = DEVICE(dev);
  187. MPQemuMsg ret = { 0 };
  188. if (dc->reset) {
  189. dc->reset(s);
  190. }
  191. ret.cmd = MPQEMU_CMD_RET;
  192. mpqemu_msg_send(&ret, ioc, errp);
  193. }