x86-iommu.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. * QEMU emulation of common X86 IOMMU
  3. *
  4. * Copyright (C) 2016 Peter Xu, Red Hat <peterx@redhat.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program; if not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include "qemu/osdep.h"
  18. #include "hw/sysbus.h"
  19. #include "hw/boards.h"
  20. #include "hw/i386/x86-iommu.h"
  21. #include "hw/qdev-properties.h"
  22. #include "hw/i386/pc.h"
  23. #include "qapi/error.h"
  24. #include "qemu/error-report.h"
  25. #include "trace.h"
  26. #include "sysemu/kvm.h"
  27. void x86_iommu_iec_register_notifier(X86IOMMUState *iommu,
  28. iec_notify_fn fn, void *data)
  29. {
  30. IEC_Notifier *notifier = g_new0(IEC_Notifier, 1);
  31. notifier->iec_notify = fn;
  32. notifier->private = data;
  33. QLIST_INSERT_HEAD(&iommu->iec_notifiers, notifier, list);
  34. }
  35. void x86_iommu_iec_notify_all(X86IOMMUState *iommu, bool global,
  36. uint32_t index, uint32_t mask)
  37. {
  38. IEC_Notifier *notifier;
  39. trace_x86_iommu_iec_notify(global, index, mask);
  40. QLIST_FOREACH(notifier, &iommu->iec_notifiers, list) {
  41. if (notifier->iec_notify) {
  42. notifier->iec_notify(notifier->private, global,
  43. index, mask);
  44. }
  45. }
  46. }
  47. /* Generate one MSI message from VTDIrq info */
  48. void x86_iommu_irq_to_msi_message(X86IOMMUIrq *irq, MSIMessage *msg_out)
  49. {
  50. X86IOMMU_MSIMessage msg = {};
  51. /* Generate address bits */
  52. msg.dest_mode = irq->dest_mode;
  53. msg.redir_hint = irq->redir_hint;
  54. msg.dest = irq->dest;
  55. msg.__addr_hi = irq->dest & 0xffffff00;
  56. msg.__addr_head = cpu_to_le32(0xfee);
  57. /* Keep this from original MSI address bits */
  58. msg.__not_used = irq->msi_addr_last_bits;
  59. /* Generate data bits */
  60. msg.vector = irq->vector;
  61. msg.delivery_mode = irq->delivery_mode;
  62. msg.level = 1;
  63. msg.trigger_mode = irq->trigger_mode;
  64. msg_out->address = msg.msi_addr;
  65. msg_out->data = msg.msi_data;
  66. }
  67. /* Default X86 IOMMU device */
  68. static X86IOMMUState *x86_iommu_default = NULL;
  69. static void x86_iommu_set_default(X86IOMMUState *x86_iommu)
  70. {
  71. assert(x86_iommu);
  72. if (x86_iommu_default) {
  73. error_report("QEMU does not support multiple vIOMMUs "
  74. "for x86 yet.");
  75. exit(1);
  76. }
  77. x86_iommu_default = x86_iommu;
  78. }
  79. X86IOMMUState *x86_iommu_get_default(void)
  80. {
  81. return x86_iommu_default;
  82. }
  83. IommuType x86_iommu_get_type(void)
  84. {
  85. return x86_iommu_default->type;
  86. }
  87. static void x86_iommu_realize(DeviceState *dev, Error **errp)
  88. {
  89. X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev);
  90. X86IOMMUClass *x86_class = X86_IOMMU_GET_CLASS(dev);
  91. MachineState *ms = MACHINE(qdev_get_machine());
  92. MachineClass *mc = MACHINE_GET_CLASS(ms);
  93. PCMachineState *pcms =
  94. PC_MACHINE(object_dynamic_cast(OBJECT(ms), TYPE_PC_MACHINE));
  95. QLIST_INIT(&x86_iommu->iec_notifiers);
  96. bool irq_all_kernel = kvm_irqchip_in_kernel() && !kvm_irqchip_is_split();
  97. if (!pcms || !pcms->bus) {
  98. error_setg(errp, "Machine-type '%s' not supported by IOMMU",
  99. mc->name);
  100. return;
  101. }
  102. /* If the user didn't specify IR, choose a default value for it */
  103. if (x86_iommu->intr_supported == ON_OFF_AUTO_AUTO) {
  104. x86_iommu->intr_supported = irq_all_kernel ?
  105. ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON;
  106. }
  107. /* Both Intel and AMD IOMMU IR only support "kernel-irqchip={off|split}" */
  108. if (x86_iommu_ir_supported(x86_iommu) && irq_all_kernel) {
  109. error_setg(errp, "Interrupt Remapping cannot work with "
  110. "kernel-irqchip=on, please use 'split|off'.");
  111. return;
  112. }
  113. if (x86_class->realize) {
  114. x86_class->realize(dev, errp);
  115. }
  116. x86_iommu_set_default(X86_IOMMU_DEVICE(dev));
  117. }
  118. static Property x86_iommu_properties[] = {
  119. DEFINE_PROP_ON_OFF_AUTO("intremap", X86IOMMUState,
  120. intr_supported, ON_OFF_AUTO_AUTO),
  121. DEFINE_PROP_BOOL("device-iotlb", X86IOMMUState, dt_supported, false),
  122. DEFINE_PROP_BOOL("pt", X86IOMMUState, pt_supported, true),
  123. DEFINE_PROP_END_OF_LIST(),
  124. };
  125. static void x86_iommu_class_init(ObjectClass *klass, void *data)
  126. {
  127. DeviceClass *dc = DEVICE_CLASS(klass);
  128. dc->realize = x86_iommu_realize;
  129. dc->props = x86_iommu_properties;
  130. }
  131. bool x86_iommu_ir_supported(X86IOMMUState *s)
  132. {
  133. return s->intr_supported == ON_OFF_AUTO_ON;
  134. }
  135. static const TypeInfo x86_iommu_info = {
  136. .name = TYPE_X86_IOMMU_DEVICE,
  137. .parent = TYPE_SYS_BUS_DEVICE,
  138. .instance_size = sizeof(X86IOMMUState),
  139. .class_init = x86_iommu_class_init,
  140. .class_size = sizeof(X86IOMMUClass),
  141. .abstract = true,
  142. };
  143. static void x86_iommu_register_types(void)
  144. {
  145. type_register_static(&x86_iommu_info);
  146. }
  147. type_init(x86_iommu_register_types)