2 * WHPX platform APIC support
4 * Copyright (c) 2011 Siemens AG
7 * Jan Kiszka <jan.kiszka@siemens.com>
8 * John Starks <jostarks@microsoft.com>
10 * This work is licensed under the terms of the GNU GPL version 2.
11 * See the COPYING file in the top-level directory.
13 #include "qemu/osdep.h"
15 #include "hw/i386/apic_internal.h"
16 #include "hw/i386/apic-msidef.h"
17 #include "hw/pci/msi.h"
18 #include "sysemu/hw_accel.h"
19 #include "sysemu/whpx.h"
20 #include "whpx-internal.h"
22 struct whpx_lapic_state
{
29 static void whpx_put_apic_state(APICCommonState
*s
,
30 struct whpx_lapic_state
*kapic
)
34 memset(kapic
, 0, sizeof(*kapic
));
35 kapic
->fields
[0x2].data
= s
->id
<< 24;
36 kapic
->fields
[0x3].data
= s
->version
| ((APIC_LVT_NB
- 1) << 16);
37 kapic
->fields
[0x8].data
= s
->tpr
;
38 kapic
->fields
[0xd].data
= s
->log_dest
<< 24;
39 kapic
->fields
[0xe].data
= s
->dest_mode
<< 28 | 0x0fffffff;
40 kapic
->fields
[0xf].data
= s
->spurious_vec
;
41 for (i
= 0; i
< 8; i
++) {
42 kapic
->fields
[0x10 + i
].data
= s
->isr
[i
];
43 kapic
->fields
[0x18 + i
].data
= s
->tmr
[i
];
44 kapic
->fields
[0x20 + i
].data
= s
->irr
[i
];
47 kapic
->fields
[0x28].data
= s
->esr
;
48 kapic
->fields
[0x30].data
= s
->icr
[0];
49 kapic
->fields
[0x31].data
= s
->icr
[1];
50 for (i
= 0; i
< APIC_LVT_NB
; i
++) {
51 kapic
->fields
[0x32 + i
].data
= s
->lvt
[i
];
54 kapic
->fields
[0x38].data
= s
->initial_count
;
55 kapic
->fields
[0x3e].data
= s
->divide_conf
;
58 static void whpx_get_apic_state(APICCommonState
*s
,
59 struct whpx_lapic_state
*kapic
)
63 s
->id
= kapic
->fields
[0x2].data
>> 24;
64 s
->tpr
= kapic
->fields
[0x8].data
;
65 s
->arb_id
= kapic
->fields
[0x9].data
;
66 s
->log_dest
= kapic
->fields
[0xd].data
>> 24;
67 s
->dest_mode
= kapic
->fields
[0xe].data
>> 28;
68 s
->spurious_vec
= kapic
->fields
[0xf].data
;
69 for (i
= 0; i
< 8; i
++) {
70 s
->isr
[i
] = kapic
->fields
[0x10 + i
].data
;
71 s
->tmr
[i
] = kapic
->fields
[0x18 + i
].data
;
72 s
->irr
[i
] = kapic
->fields
[0x20 + i
].data
;
75 s
->esr
= kapic
->fields
[0x28].data
;
76 s
->icr
[0] = kapic
->fields
[0x30].data
;
77 s
->icr
[1] = kapic
->fields
[0x31].data
;
78 for (i
= 0; i
< APIC_LVT_NB
; i
++) {
79 s
->lvt
[i
] = kapic
->fields
[0x32 + i
].data
;
82 s
->initial_count
= kapic
->fields
[0x38].data
;
83 s
->divide_conf
= kapic
->fields
[0x3e].data
;
85 v
= (s
->divide_conf
& 3) | ((s
->divide_conf
>> 1) & 4);
86 s
->count_shift
= (v
+ 1) & 7;
88 s
->initial_count_load_time
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
89 apic_next_timer(s
, s
->initial_count_load_time
);
92 static void whpx_apic_set_base(APICCommonState
*s
, uint64_t val
)
97 static void whpx_put_apic_base(CPUState
*cpu
, uint64_t val
)
100 WHV_REGISTER_VALUE reg_value
= {.Reg64
= val
};
101 WHV_REGISTER_NAME reg_name
= WHvX64RegisterApicBase
;
103 hr
= whp_dispatch
.WHvSetVirtualProcessorRegisters(
104 whpx_global
.partition
,
110 error_report("WHPX: Failed to set MSR APIC base, hr=%08lx", hr
);
114 static void whpx_apic_set_tpr(APICCommonState
*s
, uint8_t val
)
119 static uint8_t whpx_apic_get_tpr(APICCommonState
*s
)
124 static void whpx_apic_vapic_base_update(APICCommonState
*s
)
126 /* not implemented yet */
129 static void whpx_apic_put(CPUState
*cs
, run_on_cpu_data data
)
131 APICCommonState
*s
= data
.host_ptr
;
132 struct whpx_lapic_state kapic
;
135 whpx_put_apic_base(CPU(s
->cpu
), s
->apicbase
);
136 whpx_put_apic_state(s
, &kapic
);
138 hr
= whp_dispatch
.WHvSetVirtualProcessorInterruptControllerState2(
139 whpx_global
.partition
,
145 "WHvSetVirtualProcessorInterruptControllerState failed: %08lx\n",
152 void whpx_apic_get(DeviceState
*dev
)
154 APICCommonState
*s
= APIC_COMMON(dev
);
155 CPUState
*cpu
= CPU(s
->cpu
);
156 struct whpx_lapic_state kapic
;
158 HRESULT hr
= whp_dispatch
.WHvGetVirtualProcessorInterruptControllerState2(
159 whpx_global
.partition
,
166 "WHvSetVirtualProcessorInterruptControllerState failed: %08lx\n",
172 whpx_get_apic_state(s
, &kapic
);
175 static void whpx_apic_post_load(APICCommonState
*s
)
177 run_on_cpu(CPU(s
->cpu
), whpx_apic_put
, RUN_ON_CPU_HOST_PTR(s
));
180 static void whpx_apic_external_nmi(APICCommonState
*s
)
184 static void whpx_send_msi(MSIMessage
*msg
)
186 uint64_t addr
= msg
->address
;
187 uint32_t data
= msg
->data
;
188 uint8_t dest
= (addr
& MSI_ADDR_DEST_ID_MASK
) >> MSI_ADDR_DEST_ID_SHIFT
;
189 uint8_t vector
= (data
& MSI_DATA_VECTOR_MASK
) >> MSI_DATA_VECTOR_SHIFT
;
190 uint8_t dest_mode
= (addr
>> MSI_ADDR_DEST_MODE_SHIFT
) & 0x1;
191 uint8_t trigger_mode
= (data
>> MSI_DATA_TRIGGER_SHIFT
) & 0x1;
192 uint8_t delivery
= (data
>> MSI_DATA_DELIVERY_MODE_SHIFT
) & 0x7;
194 WHV_INTERRUPT_CONTROL interrupt
= {
195 /* Values correspond to delivery modes */
197 .DestinationMode
= dest_mode
?
198 WHvX64InterruptDestinationModeLogical
:
199 WHvX64InterruptDestinationModePhysical
,
201 .TriggerMode
= trigger_mode
?
202 WHvX64InterruptTriggerModeLevel
: WHvX64InterruptTriggerModeEdge
,
207 HRESULT hr
= whp_dispatch
.WHvRequestInterrupt(whpx_global
.partition
,
208 &interrupt
, sizeof(interrupt
));
210 fprintf(stderr
, "whpx: injection failed, MSI (%llx, %x) delivery: %d, "
211 "dest_mode: %d, trigger mode: %d, vector: %d, lost (%08lx)\n",
212 addr
, data
, delivery
, dest_mode
, trigger_mode
, vector
, hr
);
216 static uint64_t whpx_apic_mem_read(void *opaque
, hwaddr addr
,
222 static void whpx_apic_mem_write(void *opaque
, hwaddr addr
,
223 uint64_t data
, unsigned size
)
225 MSIMessage msg
= { .address
= addr
, .data
= data
};
229 static const MemoryRegionOps whpx_apic_io_ops
= {
230 .read
= whpx_apic_mem_read
,
231 .write
= whpx_apic_mem_write
,
232 .endianness
= DEVICE_NATIVE_ENDIAN
,
235 static void whpx_apic_reset(APICCommonState
*s
)
237 /* Not used by WHPX. */
238 s
->wait_for_sipi
= 0;
240 run_on_cpu(CPU(s
->cpu
), whpx_apic_put
, RUN_ON_CPU_HOST_PTR(s
));
243 static void whpx_apic_realize(DeviceState
*dev
, Error
**errp
)
245 APICCommonState
*s
= APIC_COMMON(dev
);
247 memory_region_init_io(&s
->io_memory
, OBJECT(s
), &whpx_apic_io_ops
, s
,
248 "whpx-apic-msi", APIC_SPACE_SIZE
);
250 msi_nonbroken
= true;
253 static void whpx_apic_class_init(ObjectClass
*klass
, void *data
)
255 APICCommonClass
*k
= APIC_COMMON_CLASS(klass
);
257 k
->realize
= whpx_apic_realize
;
258 k
->reset
= whpx_apic_reset
;
259 k
->set_base
= whpx_apic_set_base
;
260 k
->set_tpr
= whpx_apic_set_tpr
;
261 k
->get_tpr
= whpx_apic_get_tpr
;
262 k
->post_load
= whpx_apic_post_load
;
263 k
->vapic_base_update
= whpx_apic_vapic_base_update
;
264 k
->external_nmi
= whpx_apic_external_nmi
;
265 k
->send_msi
= whpx_send_msi
;
268 static const TypeInfo whpx_apic_info
= {
270 .parent
= TYPE_APIC_COMMON
,
271 .instance_size
= sizeof(APICCommonState
),
272 .class_init
= whpx_apic_class_init
,
275 static void whpx_apic_register_types(void)
277 type_register_static(&whpx_apic_info
);
280 type_init(whpx_apic_register_types
)