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/error-report.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 23 struct whpx_lapic_state { 24 struct { 25 uint32_t data; 26 uint32_t padding[3]; 27 } fields[256]; 28 }; 29 30 static void whpx_put_apic_state(APICCommonState *s, 31 struct whpx_lapic_state *kapic) 32 { 33 int i; 34 35 memset(kapic, 0, sizeof(*kapic)); 36 kapic->fields[0x2].data = s->id << 24; 37 kapic->fields[0x3].data = s->version | ((APIC_LVT_NB - 1) << 16); 38 kapic->fields[0x8].data = s->tpr; 39 kapic->fields[0xd].data = s->log_dest << 24; 40 kapic->fields[0xe].data = s->dest_mode << 28 | 0x0fffffff; 41 kapic->fields[0xf].data = s->spurious_vec; 42 for (i = 0; i < 8; i++) { 43 kapic->fields[0x10 + i].data = s->isr[i]; 44 kapic->fields[0x18 + i].data = s->tmr[i]; 45 kapic->fields[0x20 + i].data = s->irr[i]; 46 } 47 48 kapic->fields[0x28].data = s->esr; 49 kapic->fields[0x30].data = s->icr[0]; 50 kapic->fields[0x31].data = s->icr[1]; 51 for (i = 0; i < APIC_LVT_NB; i++) { 52 kapic->fields[0x32 + i].data = s->lvt[i]; 53 } 54 55 kapic->fields[0x38].data = s->initial_count; 56 kapic->fields[0x3e].data = s->divide_conf; 57 } 58 59 static void whpx_get_apic_state(APICCommonState *s, 60 struct whpx_lapic_state *kapic) 61 { 62 int i, v; 63 64 s->id = kapic->fields[0x2].data >> 24; 65 s->tpr = kapic->fields[0x8].data; 66 s->arb_id = kapic->fields[0x9].data; 67 s->log_dest = kapic->fields[0xd].data >> 24; 68 s->dest_mode = kapic->fields[0xe].data >> 28; 69 s->spurious_vec = kapic->fields[0xf].data; 70 for (i = 0; i < 8; i++) { 71 s->isr[i] = kapic->fields[0x10 + i].data; 72 s->tmr[i] = kapic->fields[0x18 + i].data; 73 s->irr[i] = kapic->fields[0x20 + i].data; 74 } 75 76 s->esr = kapic->fields[0x28].data; 77 s->icr[0] = kapic->fields[0x30].data; 78 s->icr[1] = kapic->fields[0x31].data; 79 for (i = 0; i < APIC_LVT_NB; i++) { 80 s->lvt[i] = kapic->fields[0x32 + i].data; 81 } 82 83 s->initial_count = kapic->fields[0x38].data; 84 s->divide_conf = kapic->fields[0x3e].data; 85 86 v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4); 87 s->count_shift = (v + 1) & 7; 88 89 s->initial_count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 90 apic_next_timer(s, s->initial_count_load_time); 91 } 92 93 static int whpx_apic_set_base(APICCommonState *s, uint64_t val) 94 { 95 s->apicbase = val; 96 return 0; 97 } 98 99 static void whpx_put_apic_base(CPUState *cpu, uint64_t val) 100 { 101 HRESULT hr; 102 WHV_REGISTER_VALUE reg_value = {.Reg64 = val}; 103 WHV_REGISTER_NAME reg_name = WHvX64RegisterApicBase; 104 105 hr = whp_dispatch.WHvSetVirtualProcessorRegisters( 106 whpx_global.partition, 107 cpu->cpu_index, 108 ®_name, 1, 109 ®_value); 110 111 if (FAILED(hr)) { 112 error_report("WHPX: Failed to set MSR APIC base, hr=%08lx", hr); 113 } 114 } 115 116 static void whpx_apic_set_tpr(APICCommonState *s, uint8_t val) 117 { 118 s->tpr = val; 119 } 120 121 static uint8_t whpx_apic_get_tpr(APICCommonState *s) 122 { 123 return s->tpr; 124 } 125 126 static void whpx_apic_vapic_base_update(APICCommonState *s) 127 { 128 /* not implemented yet */ 129 } 130 131 static void whpx_apic_put(CPUState *cs, run_on_cpu_data data) 132 { 133 APICCommonState *s = data.host_ptr; 134 struct whpx_lapic_state kapic; 135 HRESULT hr; 136 137 whpx_put_apic_base(CPU(s->cpu), s->apicbase); 138 whpx_put_apic_state(s, &kapic); 139 140 hr = whp_dispatch.WHvSetVirtualProcessorInterruptControllerState2( 141 whpx_global.partition, 142 cs->cpu_index, 143 &kapic, 144 sizeof(kapic)); 145 if (FAILED(hr)) { 146 fprintf(stderr, 147 "WHvSetVirtualProcessorInterruptControllerState failed: %08lx\n", 148 hr); 149 150 abort(); 151 } 152 } 153 154 void whpx_apic_get(DeviceState *dev) 155 { 156 APICCommonState *s = APIC_COMMON(dev); 157 CPUState *cpu = CPU(s->cpu); 158 struct whpx_lapic_state kapic; 159 160 HRESULT hr = whp_dispatch.WHvGetVirtualProcessorInterruptControllerState2( 161 whpx_global.partition, 162 cpu->cpu_index, 163 &kapic, 164 sizeof(kapic), 165 NULL); 166 if (FAILED(hr)) { 167 fprintf(stderr, 168 "WHvSetVirtualProcessorInterruptControllerState failed: %08lx\n", 169 hr); 170 171 abort(); 172 } 173 174 whpx_get_apic_state(s, &kapic); 175 } 176 177 static void whpx_apic_post_load(APICCommonState *s) 178 { 179 run_on_cpu(CPU(s->cpu), whpx_apic_put, RUN_ON_CPU_HOST_PTR(s)); 180 } 181 182 static void whpx_apic_external_nmi(APICCommonState *s) 183 { 184 } 185 186 static void whpx_send_msi(MSIMessage *msg) 187 { 188 uint64_t addr = msg->address; 189 uint32_t data = msg->data; 190 uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; 191 uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; 192 uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1; 193 uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1; 194 uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7; 195 196 WHV_INTERRUPT_CONTROL interrupt = { 197 /* Values correspond to delivery modes */ 198 .Type = delivery, 199 .DestinationMode = dest_mode ? 200 WHvX64InterruptDestinationModeLogical : 201 WHvX64InterruptDestinationModePhysical, 202 203 .TriggerMode = trigger_mode ? 204 WHvX64InterruptTriggerModeLevel : WHvX64InterruptTriggerModeEdge, 205 .Reserved = 0, 206 .Vector = vector, 207 .Destination = dest, 208 }; 209 HRESULT hr = whp_dispatch.WHvRequestInterrupt(whpx_global.partition, 210 &interrupt, sizeof(interrupt)); 211 if (FAILED(hr)) { 212 fprintf(stderr, "whpx: injection failed, MSI (%llx, %x) delivery: %d, " 213 "dest_mode: %d, trigger mode: %d, vector: %d, lost (%08lx)\n", 214 addr, data, delivery, dest_mode, trigger_mode, vector, hr); 215 } 216 } 217 218 static uint64_t whpx_apic_mem_read(void *opaque, hwaddr addr, 219 unsigned size) 220 { 221 return ~(uint64_t)0; 222 } 223 224 static void whpx_apic_mem_write(void *opaque, hwaddr addr, 225 uint64_t data, unsigned size) 226 { 227 MSIMessage msg = { .address = addr, .data = data }; 228 whpx_send_msi(&msg); 229 } 230 231 static const MemoryRegionOps whpx_apic_io_ops = { 232 .read = whpx_apic_mem_read, 233 .write = whpx_apic_mem_write, 234 .endianness = DEVICE_NATIVE_ENDIAN, 235 }; 236 237 static void whpx_apic_reset(APICCommonState *s) 238 { 239 /* Not used by WHPX. */ 240 s->wait_for_sipi = 0; 241 242 run_on_cpu(CPU(s->cpu), whpx_apic_put, RUN_ON_CPU_HOST_PTR(s)); 243 } 244 245 static void whpx_apic_realize(DeviceState *dev, Error **errp) 246 { 247 APICCommonState *s = APIC_COMMON(dev); 248 249 memory_region_init_io(&s->io_memory, OBJECT(s), &whpx_apic_io_ops, s, 250 "whpx-apic-msi", APIC_SPACE_SIZE); 251 252 msi_nonbroken = true; 253 } 254 255 static void whpx_apic_class_init(ObjectClass *klass, void *data) 256 { 257 APICCommonClass *k = APIC_COMMON_CLASS(klass); 258 259 k->realize = whpx_apic_realize; 260 k->reset = whpx_apic_reset; 261 k->set_base = whpx_apic_set_base; 262 k->set_tpr = whpx_apic_set_tpr; 263 k->get_tpr = whpx_apic_get_tpr; 264 k->post_load = whpx_apic_post_load; 265 k->vapic_base_update = whpx_apic_vapic_base_update; 266 k->external_nmi = whpx_apic_external_nmi; 267 k->send_msi = whpx_send_msi; 268 } 269 270 static const TypeInfo whpx_apic_info = { 271 .name = "whpx-apic", 272 .parent = TYPE_APIC_COMMON, 273 .instance_size = sizeof(APICCommonState), 274 .class_init = whpx_apic_class_init, 275 }; 276 277 static void whpx_apic_register_types(void) 278 { 279 type_register_static(&whpx_apic_info); 280 } 281 282 type_init(whpx_apic_register_types) 283