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"
14 #include "qemu/error-report.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 "whpx-internal.h"
23 struct whpx_lapic_state
{
30 static void whpx_put_apic_state(APICCommonState
*s
,
31 struct whpx_lapic_state
*kapic
)
35 memset(kapic
, 0, sizeof(*kapic
));
36 kapic
->fields
[0x2].data
= s
->id
<< 24;
37 kapic
->fields
[0x3].data
= s
->version
| ((APIC_LVT_NB
- 1) << 16);
38 kapic
->fields
[0x8].data
= s
->tpr
;
39 kapic
->fields
[0xd].data
= s
->log_dest
<< 24;
40 kapic
->fields
[0xe].data
= s
->dest_mode
<< 28 | 0x0fffffff;
41 kapic
->fields
[0xf].data
= s
->spurious_vec
;
42 for (i
= 0; i
< 8; i
++) {
43 kapic
->fields
[0x10 + i
].data
= s
->isr
[i
];
44 kapic
->fields
[0x18 + i
].data
= s
->tmr
[i
];
45 kapic
->fields
[0x20 + i
].data
= s
->irr
[i
];
48 kapic
->fields
[0x28].data
= s
->esr
;
49 kapic
->fields
[0x30].data
= s
->icr
[0];
50 kapic
->fields
[0x31].data
= s
->icr
[1];
51 for (i
= 0; i
< APIC_LVT_NB
; i
++) {
52 kapic
->fields
[0x32 + i
].data
= s
->lvt
[i
];
55 kapic
->fields
[0x38].data
= s
->initial_count
;
56 kapic
->fields
[0x3e].data
= s
->divide_conf
;
59 static void whpx_get_apic_state(APICCommonState
*s
,
60 struct whpx_lapic_state
*kapic
)
64 s
->id
= kapic
->fields
[0x2].data
>> 24;
65 s
->tpr
= kapic
->fields
[0x8].data
;
66 s
->arb_id
= kapic
->fields
[0x9].data
;
67 s
->log_dest
= kapic
->fields
[0xd].data
>> 24;
68 s
->dest_mode
= kapic
->fields
[0xe].data
>> 28;
69 s
->spurious_vec
= kapic
->fields
[0xf].data
;
70 for (i
= 0; i
< 8; i
++) {
71 s
->isr
[i
] = kapic
->fields
[0x10 + i
].data
;
72 s
->tmr
[i
] = kapic
->fields
[0x18 + i
].data
;
73 s
->irr
[i
] = kapic
->fields
[0x20 + i
].data
;
76 s
->esr
= kapic
->fields
[0x28].data
;
77 s
->icr
[0] = kapic
->fields
[0x30].data
;
78 s
->icr
[1] = kapic
->fields
[0x31].data
;
79 for (i
= 0; i
< APIC_LVT_NB
; i
++) {
80 s
->lvt
[i
] = kapic
->fields
[0x32 + i
].data
;
83 s
->initial_count
= kapic
->fields
[0x38].data
;
84 s
->divide_conf
= kapic
->fields
[0x3e].data
;
86 v
= (s
->divide_conf
& 3) | ((s
->divide_conf
>> 1) & 4);
87 s
->count_shift
= (v
+ 1) & 7;
89 s
->initial_count_load_time
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
90 apic_next_timer(s
, s
->initial_count_load_time
);
93 static void whpx_apic_set_base(APICCommonState
*s
, uint64_t val
)
98 static void whpx_put_apic_base(CPUState
*cpu
, uint64_t val
)
101 WHV_REGISTER_VALUE reg_value
= {.Reg64
= val
};
102 WHV_REGISTER_NAME reg_name
= WHvX64RegisterApicBase
;
104 hr
= whp_dispatch
.WHvSetVirtualProcessorRegisters(
105 whpx_global
.partition
,
111 error_report("WHPX: Failed to set MSR APIC base, hr=%08lx", hr
);
115 static void whpx_apic_set_tpr(APICCommonState
*s
, uint8_t val
)
120 static uint8_t whpx_apic_get_tpr(APICCommonState
*s
)
125 static void whpx_apic_vapic_base_update(APICCommonState
*s
)
127 /* not implemented yet */
130 static void whpx_apic_put(CPUState
*cs
, run_on_cpu_data data
)
132 APICCommonState
*s
= data
.host_ptr
;
133 struct whpx_lapic_state kapic
;
136 whpx_put_apic_base(CPU(s
->cpu
), s
->apicbase
);
137 whpx_put_apic_state(s
, &kapic
);
139 hr
= whp_dispatch
.WHvSetVirtualProcessorInterruptControllerState2(
140 whpx_global
.partition
,
146 "WHvSetVirtualProcessorInterruptControllerState failed: %08lx\n",
153 void whpx_apic_get(DeviceState
*dev
)
155 APICCommonState
*s
= APIC_COMMON(dev
);
156 CPUState
*cpu
= CPU(s
->cpu
);
157 struct whpx_lapic_state kapic
;
159 HRESULT hr
= whp_dispatch
.WHvGetVirtualProcessorInterruptControllerState2(
160 whpx_global
.partition
,
167 "WHvSetVirtualProcessorInterruptControllerState failed: %08lx\n",
173 whpx_get_apic_state(s
, &kapic
);
176 static void whpx_apic_post_load(APICCommonState
*s
)
178 run_on_cpu(CPU(s
->cpu
), whpx_apic_put
, RUN_ON_CPU_HOST_PTR(s
));
181 static void whpx_apic_external_nmi(APICCommonState
*s
)
185 static void whpx_send_msi(MSIMessage
*msg
)
187 uint64_t addr
= msg
->address
;
188 uint32_t data
= msg
->data
;
189 uint8_t dest
= (addr
& MSI_ADDR_DEST_ID_MASK
) >> MSI_ADDR_DEST_ID_SHIFT
;
190 uint8_t vector
= (data
& MSI_DATA_VECTOR_MASK
) >> MSI_DATA_VECTOR_SHIFT
;
191 uint8_t dest_mode
= (addr
>> MSI_ADDR_DEST_MODE_SHIFT
) & 0x1;
192 uint8_t trigger_mode
= (data
>> MSI_DATA_TRIGGER_SHIFT
) & 0x1;
193 uint8_t delivery
= (data
>> MSI_DATA_DELIVERY_MODE_SHIFT
) & 0x7;
195 WHV_INTERRUPT_CONTROL interrupt
= {
196 /* Values correspond to delivery modes */
198 .DestinationMode
= dest_mode
?
199 WHvX64InterruptDestinationModeLogical
:
200 WHvX64InterruptDestinationModePhysical
,
202 .TriggerMode
= trigger_mode
?
203 WHvX64InterruptTriggerModeLevel
: WHvX64InterruptTriggerModeEdge
,
208 HRESULT hr
= whp_dispatch
.WHvRequestInterrupt(whpx_global
.partition
,
209 &interrupt
, sizeof(interrupt
));
211 fprintf(stderr
, "whpx: injection failed, MSI (%llx, %x) delivery: %d, "
212 "dest_mode: %d, trigger mode: %d, vector: %d, lost (%08lx)\n",
213 addr
, data
, delivery
, dest_mode
, trigger_mode
, vector
, hr
);
217 static uint64_t whpx_apic_mem_read(void *opaque
, hwaddr addr
,
223 static void whpx_apic_mem_write(void *opaque
, hwaddr addr
,
224 uint64_t data
, unsigned size
)
226 MSIMessage msg
= { .address
= addr
, .data
= data
};
230 static const MemoryRegionOps whpx_apic_io_ops
= {
231 .read
= whpx_apic_mem_read
,
232 .write
= whpx_apic_mem_write
,
233 .endianness
= DEVICE_NATIVE_ENDIAN
,
236 static void whpx_apic_reset(APICCommonState
*s
)
238 /* Not used by WHPX. */
239 s
->wait_for_sipi
= 0;
241 run_on_cpu(CPU(s
->cpu
), whpx_apic_put
, RUN_ON_CPU_HOST_PTR(s
));
244 static void whpx_apic_realize(DeviceState
*dev
, Error
**errp
)
246 APICCommonState
*s
= APIC_COMMON(dev
);
248 memory_region_init_io(&s
->io_memory
, OBJECT(s
), &whpx_apic_io_ops
, s
,
249 "whpx-apic-msi", APIC_SPACE_SIZE
);
251 msi_nonbroken
= true;
254 static void whpx_apic_class_init(ObjectClass
*klass
, void *data
)
256 APICCommonClass
*k
= APIC_COMMON_CLASS(klass
);
258 k
->realize
= whpx_apic_realize
;
259 k
->reset
= whpx_apic_reset
;
260 k
->set_base
= whpx_apic_set_base
;
261 k
->set_tpr
= whpx_apic_set_tpr
;
262 k
->get_tpr
= whpx_apic_get_tpr
;
263 k
->post_load
= whpx_apic_post_load
;
264 k
->vapic_base_update
= whpx_apic_vapic_base_update
;
265 k
->external_nmi
= whpx_apic_external_nmi
;
266 k
->send_msi
= whpx_send_msi
;
269 static const TypeInfo whpx_apic_info
= {
271 .parent
= TYPE_APIC_COMMON
,
272 .instance_size
= sizeof(APICCommonState
),
273 .class_init
= whpx_apic_class_init
,
276 static void whpx_apic_register_types(void)
278 type_register_static(&whpx_apic_info
);
281 type_init(whpx_apic_register_types
)