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-common.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 "whp-dispatch.h"
23 static void whpx_put_apic_state(APICCommonState
*s
,
24 struct whpx_lapic_state
*kapic
)
28 memset(kapic
, 0, sizeof(*kapic
));
29 kapic
->fields
[0x2].data
= s
->id
<< 24;
30 kapic
->fields
[0x3].data
= s
->version
| ((APIC_LVT_NB
- 1) << 16);
31 kapic
->fields
[0x8].data
= s
->tpr
;
32 kapic
->fields
[0xd].data
= s
->log_dest
<< 24;
33 kapic
->fields
[0xe].data
= s
->dest_mode
<< 28 | 0x0fffffff;
34 kapic
->fields
[0xf].data
= s
->spurious_vec
;
35 for (i
= 0; i
< 8; i
++) {
36 kapic
->fields
[0x10 + i
].data
= s
->isr
[i
];
37 kapic
->fields
[0x18 + i
].data
= s
->tmr
[i
];
38 kapic
->fields
[0x20 + i
].data
= s
->irr
[i
];
41 kapic
->fields
[0x28].data
= s
->esr
;
42 kapic
->fields
[0x30].data
= s
->icr
[0];
43 kapic
->fields
[0x31].data
= s
->icr
[1];
44 for (i
= 0; i
< APIC_LVT_NB
; i
++) {
45 kapic
->fields
[0x32 + i
].data
= s
->lvt
[i
];
48 kapic
->fields
[0x38].data
= s
->initial_count
;
49 kapic
->fields
[0x3e].data
= s
->divide_conf
;
52 static void whpx_get_apic_state(APICCommonState
*s
,
53 struct whpx_lapic_state
*kapic
)
57 s
->id
= kapic
->fields
[0x2].data
>> 24;
58 s
->tpr
= kapic
->fields
[0x8].data
;
59 s
->arb_id
= kapic
->fields
[0x9].data
;
60 s
->log_dest
= kapic
->fields
[0xd].data
>> 24;
61 s
->dest_mode
= kapic
->fields
[0xe].data
>> 28;
62 s
->spurious_vec
= kapic
->fields
[0xf].data
;
63 for (i
= 0; i
< 8; i
++) {
64 s
->isr
[i
] = kapic
->fields
[0x10 + i
].data
;
65 s
->tmr
[i
] = kapic
->fields
[0x18 + i
].data
;
66 s
->irr
[i
] = kapic
->fields
[0x20 + i
].data
;
69 s
->esr
= kapic
->fields
[0x28].data
;
70 s
->icr
[0] = kapic
->fields
[0x30].data
;
71 s
->icr
[1] = kapic
->fields
[0x31].data
;
72 for (i
= 0; i
< APIC_LVT_NB
; i
++) {
73 s
->lvt
[i
] = kapic
->fields
[0x32 + i
].data
;
76 s
->initial_count
= kapic
->fields
[0x38].data
;
77 s
->divide_conf
= kapic
->fields
[0x3e].data
;
79 v
= (s
->divide_conf
& 3) | ((s
->divide_conf
>> 1) & 4);
80 s
->count_shift
= (v
+ 1) & 7;
82 s
->initial_count_load_time
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
83 apic_next_timer(s
, s
->initial_count_load_time
);
86 static void whpx_apic_set_base(APICCommonState
*s
, uint64_t val
)
91 static void whpx_put_apic_base(CPUState
*cpu
, uint64_t val
)
94 WHV_REGISTER_VALUE reg_value
= {.Reg64
= val
};
95 WHV_REGISTER_NAME reg_name
= WHvX64RegisterApicBase
;
97 hr
= whp_dispatch
.WHvSetVirtualProcessorRegisters(
98 whpx_global
.partition
,
104 error_report("WHPX: Failed to set MSR APIC base, hr=%08lx", hr
);
108 static void whpx_apic_set_tpr(APICCommonState
*s
, uint8_t val
)
113 static uint8_t whpx_apic_get_tpr(APICCommonState
*s
)
118 static void whpx_apic_vapic_base_update(APICCommonState
*s
)
120 /* not implemented yet */
123 static void whpx_apic_put(CPUState
*cs
, run_on_cpu_data data
)
125 APICCommonState
*s
= data
.host_ptr
;
126 struct whpx_lapic_state kapic
;
129 whpx_put_apic_base(CPU(s
->cpu
), s
->apicbase
);
130 whpx_put_apic_state(s
, &kapic
);
132 hr
= whp_dispatch
.WHvSetVirtualProcessorInterruptControllerState2(
133 whpx_global
.partition
,
139 "WHvSetVirtualProcessorInterruptControllerState failed: %08lx\n",
146 void whpx_apic_get(DeviceState
*dev
)
148 APICCommonState
*s
= APIC_COMMON(dev
);
149 CPUState
*cpu
= CPU(s
->cpu
);
150 struct whpx_lapic_state kapic
;
152 HRESULT hr
= whp_dispatch
.WHvGetVirtualProcessorInterruptControllerState2(
153 whpx_global
.partition
,
160 "WHvSetVirtualProcessorInterruptControllerState failed: %08lx\n",
166 whpx_get_apic_state(s
, &kapic
);
169 static void whpx_apic_post_load(APICCommonState
*s
)
171 run_on_cpu(CPU(s
->cpu
), whpx_apic_put
, RUN_ON_CPU_HOST_PTR(s
));
174 static void whpx_apic_external_nmi(APICCommonState
*s
)
178 static void whpx_send_msi(MSIMessage
*msg
)
180 uint64_t addr
= msg
->address
;
181 uint32_t data
= msg
->data
;
182 uint8_t dest
= (addr
& MSI_ADDR_DEST_ID_MASK
) >> MSI_ADDR_DEST_ID_SHIFT
;
183 uint8_t vector
= (data
& MSI_DATA_VECTOR_MASK
) >> MSI_DATA_VECTOR_SHIFT
;
184 uint8_t dest_mode
= (addr
>> MSI_ADDR_DEST_MODE_SHIFT
) & 0x1;
185 uint8_t trigger_mode
= (data
>> MSI_DATA_TRIGGER_SHIFT
) & 0x1;
186 uint8_t delivery
= (data
>> MSI_DATA_DELIVERY_MODE_SHIFT
) & 0x7;
188 WHV_INTERRUPT_CONTROL interrupt
= {
189 /* Values correspond to delivery modes */
191 .DestinationMode
= dest_mode
?
192 WHvX64InterruptDestinationModeLogical
:
193 WHvX64InterruptDestinationModePhysical
,
195 .TriggerMode
= trigger_mode
?
196 WHvX64InterruptTriggerModeLevel
: WHvX64InterruptTriggerModeEdge
,
201 HRESULT hr
= whp_dispatch
.WHvRequestInterrupt(whpx_global
.partition
,
202 &interrupt
, sizeof(interrupt
));
204 fprintf(stderr
, "whpx: injection failed, MSI (%llx, %x) delivery: %d, "
205 "dest_mode: %d, trigger mode: %d, vector: %d, lost (%08lx)\n",
206 addr
, data
, delivery
, dest_mode
, trigger_mode
, vector
, hr
);
210 static uint64_t whpx_apic_mem_read(void *opaque
, hwaddr addr
,
216 static void whpx_apic_mem_write(void *opaque
, hwaddr addr
,
217 uint64_t data
, unsigned size
)
219 MSIMessage msg
= { .address
= addr
, .data
= data
};
223 static const MemoryRegionOps whpx_apic_io_ops
= {
224 .read
= whpx_apic_mem_read
,
225 .write
= whpx_apic_mem_write
,
226 .endianness
= DEVICE_NATIVE_ENDIAN
,
229 static void whpx_apic_reset(APICCommonState
*s
)
231 /* Not used by WHPX. */
232 s
->wait_for_sipi
= 0;
234 run_on_cpu(CPU(s
->cpu
), whpx_apic_put
, RUN_ON_CPU_HOST_PTR(s
));
237 static void whpx_apic_realize(DeviceState
*dev
, Error
**errp
)
239 APICCommonState
*s
= APIC_COMMON(dev
);
241 memory_region_init_io(&s
->io_memory
, OBJECT(s
), &whpx_apic_io_ops
, s
,
242 "whpx-apic-msi", APIC_SPACE_SIZE
);
244 msi_nonbroken
= true;
247 static void whpx_apic_class_init(ObjectClass
*klass
, void *data
)
249 APICCommonClass
*k
= APIC_COMMON_CLASS(klass
);
251 k
->realize
= whpx_apic_realize
;
252 k
->reset
= whpx_apic_reset
;
253 k
->set_base
= whpx_apic_set_base
;
254 k
->set_tpr
= whpx_apic_set_tpr
;
255 k
->get_tpr
= whpx_apic_get_tpr
;
256 k
->post_load
= whpx_apic_post_load
;
257 k
->vapic_base_update
= whpx_apic_vapic_base_update
;
258 k
->external_nmi
= whpx_apic_external_nmi
;
259 k
->send_msi
= whpx_send_msi
;
262 static const TypeInfo whpx_apic_info
= {
264 .parent
= TYPE_APIC_COMMON
,
265 .instance_size
= sizeof(APICCommonState
),
266 .class_init
= whpx_apic_class_init
,
269 static void whpx_apic_register_types(void)
271 type_register_static(&whpx_apic_info
);
274 type_init(whpx_apic_register_types
)