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