PageRenderTime 568ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/target/i386/whpx/whpx-apic.c

https://gitlab.com/paelzer/qemu
C | 281 lines | 222 code | 44 blank | 15 comment | 8 complexity | 8d089176daf184e486a438cf59fd7dba MD5 | raw file
  1. /*
  2. * WHPX platform APIC support
  3. *
  4. * Copyright (c) 2011 Siemens AG
  5. *
  6. * Authors:
  7. * Jan Kiszka <jan.kiszka@siemens.com>
  8. * John Starks <jostarks@microsoft.com>
  9. *
  10. * This work is licensed under the terms of the GNU GPL version 2.
  11. * See the COPYING file in the top-level directory.
  12. */
  13. #include "qemu/osdep.h"
  14. #include "qemu-common.h"
  15. #include "cpu.h"
  16. #include "hw/i386/apic_internal.h"
  17. #include "hw/i386/apic-msidef.h"
  18. #include "hw/pci/msi.h"
  19. #include "sysemu/hw_accel.h"
  20. #include "sysemu/whpx.h"
  21. #include "whpx-internal.h"
  22. struct whpx_lapic_state {
  23. struct {
  24. uint32_t data;
  25. uint32_t padding[3];
  26. } fields[256];
  27. };
  28. static void whpx_put_apic_state(APICCommonState *s,
  29. struct whpx_lapic_state *kapic)
  30. {
  31. int i;
  32. memset(kapic, 0, sizeof(*kapic));
  33. kapic->fields[0x2].data = s->id << 24;
  34. kapic->fields[0x3].data = s->version | ((APIC_LVT_NB - 1) << 16);
  35. kapic->fields[0x8].data = s->tpr;
  36. kapic->fields[0xd].data = s->log_dest << 24;
  37. kapic->fields[0xe].data = s->dest_mode << 28 | 0x0fffffff;
  38. kapic->fields[0xf].data = s->spurious_vec;
  39. for (i = 0; i < 8; i++) {
  40. kapic->fields[0x10 + i].data = s->isr[i];
  41. kapic->fields[0x18 + i].data = s->tmr[i];
  42. kapic->fields[0x20 + i].data = s->irr[i];
  43. }
  44. kapic->fields[0x28].data = s->esr;
  45. kapic->fields[0x30].data = s->icr[0];
  46. kapic->fields[0x31].data = s->icr[1];
  47. for (i = 0; i < APIC_LVT_NB; i++) {
  48. kapic->fields[0x32 + i].data = s->lvt[i];
  49. }
  50. kapic->fields[0x38].data = s->initial_count;
  51. kapic->fields[0x3e].data = s->divide_conf;
  52. }
  53. static void whpx_get_apic_state(APICCommonState *s,
  54. struct whpx_lapic_state *kapic)
  55. {
  56. int i, v;
  57. s->id = kapic->fields[0x2].data >> 24;
  58. s->tpr = kapic->fields[0x8].data;
  59. s->arb_id = kapic->fields[0x9].data;
  60. s->log_dest = kapic->fields[0xd].data >> 24;
  61. s->dest_mode = kapic->fields[0xe].data >> 28;
  62. s->spurious_vec = kapic->fields[0xf].data;
  63. for (i = 0; i < 8; i++) {
  64. s->isr[i] = kapic->fields[0x10 + i].data;
  65. s->tmr[i] = kapic->fields[0x18 + i].data;
  66. s->irr[i] = kapic->fields[0x20 + i].data;
  67. }
  68. s->esr = kapic->fields[0x28].data;
  69. s->icr[0] = kapic->fields[0x30].data;
  70. s->icr[1] = kapic->fields[0x31].data;
  71. for (i = 0; i < APIC_LVT_NB; i++) {
  72. s->lvt[i] = kapic->fields[0x32 + i].data;
  73. }
  74. s->initial_count = kapic->fields[0x38].data;
  75. s->divide_conf = kapic->fields[0x3e].data;
  76. v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
  77. s->count_shift = (v + 1) & 7;
  78. s->initial_count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
  79. apic_next_timer(s, s->initial_count_load_time);
  80. }
  81. static void whpx_apic_set_base(APICCommonState *s, uint64_t val)
  82. {
  83. s->apicbase = val;
  84. }
  85. static void whpx_put_apic_base(CPUState *cpu, uint64_t val)
  86. {
  87. HRESULT hr;
  88. WHV_REGISTER_VALUE reg_value = {.Reg64 = val};
  89. WHV_REGISTER_NAME reg_name = WHvX64RegisterApicBase;
  90. hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
  91. whpx_global.partition,
  92. cpu->cpu_index,
  93. &reg_name, 1,
  94. &reg_value);
  95. if (FAILED(hr)) {
  96. error_report("WHPX: Failed to set MSR APIC base, hr=%08lx", hr);
  97. }
  98. }
  99. static void whpx_apic_set_tpr(APICCommonState *s, uint8_t val)
  100. {
  101. s->tpr = val;
  102. }
  103. static uint8_t whpx_apic_get_tpr(APICCommonState *s)
  104. {
  105. return s->tpr;
  106. }
  107. static void whpx_apic_vapic_base_update(APICCommonState *s)
  108. {
  109. /* not implemented yet */
  110. }
  111. static void whpx_apic_put(CPUState *cs, run_on_cpu_data data)
  112. {
  113. APICCommonState *s = data.host_ptr;
  114. struct whpx_lapic_state kapic;
  115. HRESULT hr;
  116. whpx_put_apic_base(CPU(s->cpu), s->apicbase);
  117. whpx_put_apic_state(s, &kapic);
  118. hr = whp_dispatch.WHvSetVirtualProcessorInterruptControllerState2(
  119. whpx_global.partition,
  120. cs->cpu_index,
  121. &kapic,
  122. sizeof(kapic));
  123. if (FAILED(hr)) {
  124. fprintf(stderr,
  125. "WHvSetVirtualProcessorInterruptControllerState failed: %08lx\n",
  126. hr);
  127. abort();
  128. }
  129. }
  130. void whpx_apic_get(DeviceState *dev)
  131. {
  132. APICCommonState *s = APIC_COMMON(dev);
  133. CPUState *cpu = CPU(s->cpu);
  134. struct whpx_lapic_state kapic;
  135. HRESULT hr = whp_dispatch.WHvGetVirtualProcessorInterruptControllerState2(
  136. whpx_global.partition,
  137. cpu->cpu_index,
  138. &kapic,
  139. sizeof(kapic),
  140. NULL);
  141. if (FAILED(hr)) {
  142. fprintf(stderr,
  143. "WHvSetVirtualProcessorInterruptControllerState failed: %08lx\n",
  144. hr);
  145. abort();
  146. }
  147. whpx_get_apic_state(s, &kapic);
  148. }
  149. static void whpx_apic_post_load(APICCommonState *s)
  150. {
  151. run_on_cpu(CPU(s->cpu), whpx_apic_put, RUN_ON_CPU_HOST_PTR(s));
  152. }
  153. static void whpx_apic_external_nmi(APICCommonState *s)
  154. {
  155. }
  156. static void whpx_send_msi(MSIMessage *msg)
  157. {
  158. uint64_t addr = msg->address;
  159. uint32_t data = msg->data;
  160. uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
  161. uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
  162. uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
  163. uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
  164. uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
  165. WHV_INTERRUPT_CONTROL interrupt = {
  166. /* Values correspond to delivery modes */
  167. .Type = delivery,
  168. .DestinationMode = dest_mode ?
  169. WHvX64InterruptDestinationModeLogical :
  170. WHvX64InterruptDestinationModePhysical,
  171. .TriggerMode = trigger_mode ?
  172. WHvX64InterruptTriggerModeLevel : WHvX64InterruptTriggerModeEdge,
  173. .Reserved = 0,
  174. .Vector = vector,
  175. .Destination = dest,
  176. };
  177. HRESULT hr = whp_dispatch.WHvRequestInterrupt(whpx_global.partition,
  178. &interrupt, sizeof(interrupt));
  179. if (FAILED(hr)) {
  180. fprintf(stderr, "whpx: injection failed, MSI (%llx, %x) delivery: %d, "
  181. "dest_mode: %d, trigger mode: %d, vector: %d, lost (%08lx)\n",
  182. addr, data, delivery, dest_mode, trigger_mode, vector, hr);
  183. }
  184. }
  185. static uint64_t whpx_apic_mem_read(void *opaque, hwaddr addr,
  186. unsigned size)
  187. {
  188. return ~(uint64_t)0;
  189. }
  190. static void whpx_apic_mem_write(void *opaque, hwaddr addr,
  191. uint64_t data, unsigned size)
  192. {
  193. MSIMessage msg = { .address = addr, .data = data };
  194. whpx_send_msi(&msg);
  195. }
  196. static const MemoryRegionOps whpx_apic_io_ops = {
  197. .read = whpx_apic_mem_read,
  198. .write = whpx_apic_mem_write,
  199. .endianness = DEVICE_NATIVE_ENDIAN,
  200. };
  201. static void whpx_apic_reset(APICCommonState *s)
  202. {
  203. /* Not used by WHPX. */
  204. s->wait_for_sipi = 0;
  205. run_on_cpu(CPU(s->cpu), whpx_apic_put, RUN_ON_CPU_HOST_PTR(s));
  206. }
  207. static void whpx_apic_realize(DeviceState *dev, Error **errp)
  208. {
  209. APICCommonState *s = APIC_COMMON(dev);
  210. memory_region_init_io(&s->io_memory, OBJECT(s), &whpx_apic_io_ops, s,
  211. "whpx-apic-msi", APIC_SPACE_SIZE);
  212. msi_nonbroken = true;
  213. }
  214. static void whpx_apic_class_init(ObjectClass *klass, void *data)
  215. {
  216. APICCommonClass *k = APIC_COMMON_CLASS(klass);
  217. k->realize = whpx_apic_realize;
  218. k->reset = whpx_apic_reset;
  219. k->set_base = whpx_apic_set_base;
  220. k->set_tpr = whpx_apic_set_tpr;
  221. k->get_tpr = whpx_apic_get_tpr;
  222. k->post_load = whpx_apic_post_load;
  223. k->vapic_base_update = whpx_apic_vapic_base_update;
  224. k->external_nmi = whpx_apic_external_nmi;
  225. k->send_msi = whpx_send_msi;
  226. }
  227. static const TypeInfo whpx_apic_info = {
  228. .name = "whpx-apic",
  229. .parent = TYPE_APIC_COMMON,
  230. .instance_size = sizeof(APICCommonState),
  231. .class_init = whpx_apic_class_init,
  232. };
  233. static void whpx_apic_register_types(void)
  234. {
  235. type_register_static(&whpx_apic_info);
  236. }
  237. type_init(whpx_apic_register_types)