arm_gicv3_its_kvm.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * KVM-based ITS implementation for a GICv3-based system
  3. *
  4. * Copyright (c) 2015 Samsung Electronics Co., Ltd.
  5. * Written by Pavel Fedin <p.fedin@samsung.com>
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include "qemu/osdep.h"
  21. #include "qapi/error.h"
  22. #include "qemu/module.h"
  23. #include "qemu/error-report.h"
  24. #include "hw/intc/arm_gicv3_its_common.h"
  25. #include "hw/qdev-properties.h"
  26. #include "system/runstate.h"
  27. #include "system/kvm.h"
  28. #include "kvm_arm.h"
  29. #include "migration/blocker.h"
  30. #include "qom/object.h"
  31. #define TYPE_KVM_ARM_ITS "arm-its-kvm"
  32. typedef struct KVMARMITSClass KVMARMITSClass;
  33. /* This is reusing the GICv3ITSState typedef from ARM_GICV3_ITS_COMMON */
  34. DECLARE_OBJ_CHECKERS(GICv3ITSState, KVMARMITSClass,
  35. KVM_ARM_ITS, TYPE_KVM_ARM_ITS)
  36. struct KVMARMITSClass {
  37. GICv3ITSCommonClass parent_class;
  38. ResettablePhases parent_phases;
  39. };
  40. static int kvm_its_send_msi(GICv3ITSState *s, uint32_t value, uint16_t devid)
  41. {
  42. struct kvm_msi msi;
  43. if (unlikely(!s->translater_gpa_known)) {
  44. MemoryRegion *mr = &s->iomem_its_translation;
  45. MemoryRegionSection mrs;
  46. mrs = memory_region_find(mr, 0, 1);
  47. memory_region_unref(mrs.mr);
  48. s->gits_translater_gpa = mrs.offset_within_address_space + 0x40;
  49. s->translater_gpa_known = true;
  50. }
  51. msi.address_lo = extract64(s->gits_translater_gpa, 0, 32);
  52. msi.address_hi = extract64(s->gits_translater_gpa, 32, 32);
  53. msi.data = le32_to_cpu(value);
  54. msi.flags = KVM_MSI_VALID_DEVID;
  55. msi.devid = devid;
  56. memset(msi.pad, 0, sizeof(msi.pad));
  57. return kvm_vm_ioctl(kvm_state, KVM_SIGNAL_MSI, &msi);
  58. }
  59. /**
  60. * vm_change_state_handler - VM change state callback aiming at flushing
  61. * ITS tables into guest RAM
  62. *
  63. * The tables get flushed to guest RAM whenever the VM gets stopped.
  64. */
  65. static void vm_change_state_handler(void *opaque, bool running,
  66. RunState state)
  67. {
  68. GICv3ITSState *s = (GICv3ITSState *)opaque;
  69. Error *err = NULL;
  70. if (running) {
  71. return;
  72. }
  73. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
  74. KVM_DEV_ARM_ITS_SAVE_TABLES, NULL, true, &err);
  75. if (err) {
  76. error_report_err(err);
  77. }
  78. }
  79. static void kvm_arm_its_realize(DeviceState *dev, Error **errp)
  80. {
  81. GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
  82. s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_ITS, false);
  83. if (s->dev_fd < 0) {
  84. error_setg_errno(errp, -s->dev_fd, "error creating in-kernel ITS");
  85. return;
  86. }
  87. /* explicit init of the ITS */
  88. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
  89. KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true, &error_abort);
  90. /* register the base address */
  91. kvm_arm_register_device(&s->iomem_its_cntrl, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
  92. KVM_VGIC_ITS_ADDR_TYPE, s->dev_fd, 0);
  93. gicv3_add_its(s->gicv3, dev);
  94. gicv3_its_init_mmio(s, NULL, NULL);
  95. if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
  96. GITS_CTLR)) {
  97. error_setg(&s->migration_blocker, "This operating system kernel "
  98. "does not support vITS migration");
  99. if (migrate_add_blocker(&s->migration_blocker, errp) < 0) {
  100. return;
  101. }
  102. } else {
  103. qemu_add_vm_change_state_handler(vm_change_state_handler, s);
  104. }
  105. kvm_msi_use_devid = true;
  106. kvm_gsi_direct_mapping = false;
  107. kvm_msi_via_irqfd_allowed = true;
  108. }
  109. /**
  110. * kvm_arm_its_pre_save - handles the saving of ITS registers.
  111. * ITS tables are flushed into guest RAM separately and earlier,
  112. * through the VM change state handler, since at the moment pre_save()
  113. * is called, the guest RAM has already been saved.
  114. */
  115. static void kvm_arm_its_pre_save(GICv3ITSState *s)
  116. {
  117. int i;
  118. for (i = 0; i < 8; i++) {
  119. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
  120. GITS_BASER + i * 8, &s->baser[i], false,
  121. &error_abort);
  122. }
  123. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
  124. GITS_CTLR, &s->ctlr, false, &error_abort);
  125. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
  126. GITS_CBASER, &s->cbaser, false, &error_abort);
  127. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
  128. GITS_CREADR, &s->creadr, false, &error_abort);
  129. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
  130. GITS_CWRITER, &s->cwriter, false, &error_abort);
  131. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
  132. GITS_IIDR, &s->iidr, false, &error_abort);
  133. }
  134. /**
  135. * kvm_arm_its_post_load - Restore both the ITS registers and tables
  136. */
  137. static void kvm_arm_its_post_load(GICv3ITSState *s)
  138. {
  139. int i;
  140. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
  141. GITS_IIDR, &s->iidr, true, &error_abort);
  142. /*
  143. * must be written before GITS_CREADR since GITS_CBASER write
  144. * access resets GITS_CREADR.
  145. */
  146. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
  147. GITS_CBASER, &s->cbaser, true, &error_abort);
  148. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
  149. GITS_CREADR, &s->creadr, true, &error_abort);
  150. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
  151. GITS_CWRITER, &s->cwriter, true, &error_abort);
  152. for (i = 0; i < 8; i++) {
  153. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
  154. GITS_BASER + i * 8, &s->baser[i], true,
  155. &error_abort);
  156. }
  157. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
  158. KVM_DEV_ARM_ITS_RESTORE_TABLES, NULL, true,
  159. &error_abort);
  160. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
  161. GITS_CTLR, &s->ctlr, true, &error_abort);
  162. }
  163. static void kvm_arm_its_reset_hold(Object *obj, ResetType type)
  164. {
  165. GICv3ITSState *s = ARM_GICV3_ITS_COMMON(obj);
  166. KVMARMITSClass *c = KVM_ARM_ITS_GET_CLASS(s);
  167. int i;
  168. if (c->parent_phases.hold) {
  169. c->parent_phases.hold(obj, type);
  170. }
  171. if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
  172. KVM_DEV_ARM_ITS_CTRL_RESET)) {
  173. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
  174. KVM_DEV_ARM_ITS_CTRL_RESET, NULL, true, &error_abort);
  175. return;
  176. }
  177. warn_report("ITS KVM: full reset is not supported by the host kernel");
  178. if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
  179. GITS_CTLR)) {
  180. return;
  181. }
  182. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
  183. GITS_CTLR, &s->ctlr, true, &error_abort);
  184. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
  185. GITS_CBASER, &s->cbaser, true, &error_abort);
  186. for (i = 0; i < 8; i++) {
  187. kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
  188. GITS_BASER + i * 8, &s->baser[i], true,
  189. &error_abort);
  190. }
  191. }
  192. static const Property kvm_arm_its_props[] = {
  193. DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "kvm-arm-gicv3",
  194. GICv3State *),
  195. };
  196. static void kvm_arm_its_class_init(ObjectClass *klass, void *data)
  197. {
  198. DeviceClass *dc = DEVICE_CLASS(klass);
  199. ResettableClass *rc = RESETTABLE_CLASS(klass);
  200. GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass);
  201. KVMARMITSClass *ic = KVM_ARM_ITS_CLASS(klass);
  202. dc->realize = kvm_arm_its_realize;
  203. device_class_set_props(dc, kvm_arm_its_props);
  204. resettable_class_set_parent_phases(rc, NULL, kvm_arm_its_reset_hold, NULL,
  205. &ic->parent_phases);
  206. icc->send_msi = kvm_its_send_msi;
  207. icc->pre_save = kvm_arm_its_pre_save;
  208. icc->post_load = kvm_arm_its_post_load;
  209. }
  210. static const TypeInfo kvm_arm_its_info = {
  211. .name = TYPE_KVM_ARM_ITS,
  212. .parent = TYPE_ARM_GICV3_ITS_COMMON,
  213. .instance_size = sizeof(GICv3ITSState),
  214. .class_init = kvm_arm_its_class_init,
  215. .class_size = sizeof(KVMARMITSClass),
  216. };
  217. static void kvm_arm_its_register_types(void)
  218. {
  219. type_register_static(&kvm_arm_its_info);
  220. }
  221. type_init(kvm_arm_its_register_types)