xref: /qemu/target/i386/whpx/whpx-apic.c (revision df9ae6aa84b92bb73c84194dc60f938e2495594c)
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              &reg_name, 1,
109faf20793SSunil Muthuswamy              &reg_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