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