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