2 * KVM in-kernel APIC support
4 * Copyright (c) 2011 Siemens AG
7 * Jan Kiszka <jan.kiszka@siemens.com>
9 * This work is licensed under the terms of the GNU GPL version 2.
10 * See the COPYING file in the top-level directory.
12 #include "hw/apic_internal.h"
15 static inline void kvm_apic_set_reg(struct kvm_lapic_state
*kapic
,
16 int reg_id
, uint32_t val
)
18 *((uint32_t *)(kapic
->regs
+ (reg_id
<< 4))) = val
;
21 static inline uint32_t kvm_apic_get_reg(struct kvm_lapic_state
*kapic
,
24 return *((uint32_t *)(kapic
->regs
+ (reg_id
<< 4)));
27 void kvm_put_apic_state(DeviceState
*d
, struct kvm_lapic_state
*kapic
)
29 APICCommonState
*s
= DO_UPCAST(APICCommonState
, busdev
.qdev
, d
);
32 memset(kapic
, 0, sizeof(kapic
));
33 kvm_apic_set_reg(kapic
, 0x2, s
->id
<< 24);
34 kvm_apic_set_reg(kapic
, 0x8, s
->tpr
);
35 kvm_apic_set_reg(kapic
, 0xd, s
->log_dest
<< 24);
36 kvm_apic_set_reg(kapic
, 0xe, s
->dest_mode
<< 28 | 0x0fffffff);
37 kvm_apic_set_reg(kapic
, 0xf, s
->spurious_vec
);
38 for (i
= 0; i
< 8; i
++) {
39 kvm_apic_set_reg(kapic
, 0x10 + i
, s
->isr
[i
]);
40 kvm_apic_set_reg(kapic
, 0x18 + i
, s
->tmr
[i
]);
41 kvm_apic_set_reg(kapic
, 0x20 + i
, s
->irr
[i
]);
43 kvm_apic_set_reg(kapic
, 0x28, s
->esr
);
44 kvm_apic_set_reg(kapic
, 0x30, s
->icr
[0]);
45 kvm_apic_set_reg(kapic
, 0x31, s
->icr
[1]);
46 for (i
= 0; i
< APIC_LVT_NB
; i
++) {
47 kvm_apic_set_reg(kapic
, 0x32 + i
, s
->lvt
[i
]);
49 kvm_apic_set_reg(kapic
, 0x38, s
->initial_count
);
50 kvm_apic_set_reg(kapic
, 0x3e, s
->divide_conf
);
53 void kvm_get_apic_state(DeviceState
*d
, struct kvm_lapic_state
*kapic
)
55 APICCommonState
*s
= DO_UPCAST(APICCommonState
, busdev
.qdev
, d
);
58 s
->id
= kvm_apic_get_reg(kapic
, 0x2) >> 24;
59 s
->tpr
= kvm_apic_get_reg(kapic
, 0x8);
60 s
->arb_id
= kvm_apic_get_reg(kapic
, 0x9);
61 s
->log_dest
= kvm_apic_get_reg(kapic
, 0xd) >> 24;
62 s
->dest_mode
= kvm_apic_get_reg(kapic
, 0xe) >> 28;
63 s
->spurious_vec
= kvm_apic_get_reg(kapic
, 0xf);
64 for (i
= 0; i
< 8; i
++) {
65 s
->isr
[i
] = kvm_apic_get_reg(kapic
, 0x10 + i
);
66 s
->tmr
[i
] = kvm_apic_get_reg(kapic
, 0x18 + i
);
67 s
->irr
[i
] = kvm_apic_get_reg(kapic
, 0x20 + i
);
69 s
->esr
= kvm_apic_get_reg(kapic
, 0x28);
70 s
->icr
[0] = kvm_apic_get_reg(kapic
, 0x30);
71 s
->icr
[1] = kvm_apic_get_reg(kapic
, 0x31);
72 for (i
= 0; i
< APIC_LVT_NB
; i
++) {
73 s
->lvt
[i
] = kvm_apic_get_reg(kapic
, 0x32 + i
);
75 s
->initial_count
= kvm_apic_get_reg(kapic
, 0x38);
76 s
->divide_conf
= kvm_apic_get_reg(kapic
, 0x3e);
78 v
= (s
->divide_conf
& 3) | ((s
->divide_conf
>> 1) & 4);
79 s
->count_shift
= (v
+ 1) & 7;
81 s
->initial_count_load_time
= qemu_get_clock_ns(vm_clock
);
82 apic_next_timer(s
, s
->initial_count_load_time
);
85 static void kvm_apic_set_base(APICCommonState
*s
, uint64_t val
)
90 static void kvm_apic_set_tpr(APICCommonState
*s
, uint8_t val
)
92 s
->tpr
= (val
& 0x0f) << 4;
95 static void do_inject_external_nmi(void *data
)
97 APICCommonState
*s
= data
;
98 CPUState
*env
= s
->cpu_env
;
102 cpu_synchronize_state(env
);
104 lvt
= s
->lvt
[APIC_LVT_LINT1
];
105 if (!(lvt
& APIC_LVT_MASKED
) && ((lvt
>> 8) & 7) == APIC_DM_NMI
) {
106 ret
= kvm_vcpu_ioctl(env
, KVM_NMI
);
108 fprintf(stderr
, "KVM: injection failed, NMI lost (%s)\n",
114 static void kvm_apic_external_nmi(APICCommonState
*s
)
116 run_on_cpu(s
->cpu_env
, do_inject_external_nmi
, s
);
119 static void kvm_apic_init(APICCommonState
*s
)
121 memory_region_init_reservation(&s
->io_memory
, "kvm-apic-msi",
125 static void kvm_apic_class_init(ObjectClass
*klass
, void *data
)
127 APICCommonClass
*k
= APIC_COMMON_CLASS(klass
);
129 k
->init
= kvm_apic_init
;
130 k
->set_base
= kvm_apic_set_base
;
131 k
->set_tpr
= kvm_apic_set_tpr
;
132 k
->external_nmi
= kvm_apic_external_nmi
;
135 static TypeInfo kvm_apic_info
= {
137 .parent
= TYPE_APIC_COMMON
,
138 .instance_size
= sizeof(APICCommonState
),
139 .class_init
= kvm_apic_class_init
,
142 static void kvm_apic_register_device(void)
144 type_register_static(&kvm_apic_info
);
147 device_init(kvm_apic_register_device
)