master
c 237 lines 6.68 KB
Raw
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3 * ARM Generic Interrupt Controller using HVF platform support
4 *
5 * Copyright (c) 2025 Mohamed Mediouni
6 * Based on vGICv3 KVM code by Pavel Fedin
7 *
8 */
9
10 #include "qemu/osdep.h"
11 #include "qapi/error.h"
12 #include "hw/intc/arm_gicv3_common.h"
13 #include "qemu/error-report.h"
14 #include "qemu/module.h"
15 #include "system/runstate.h"
16 #include "system/whpx.h"
17 #include "system/whpx-internal.h"
18 #include "gicv3_internal.h"
19 #include "vgic_common.h"
20 #include "migration/blocker.h"
21 #include "qom/object.h"
22 #include "target/arm/cpregs.h"
23
24 #include "hw/arm/bsa.h"
25 #include <winhvplatform.h>
26 #include <winhvplatformdefs.h>
27 #include <winnt.h>
28
29 struct WHPXARMGICv3Class {
30 ARMGICv3CommonClass parent_class;
31 DeviceRealize parent_realize;
32 ResettablePhases parent_phases;
33 };
34
35 OBJECT_DECLARE_TYPE(GICv3State, WHPXARMGICv3Class, WHPX_GICV3)
36
37 /* TODO: Implement GIC state save-restore */
38 static void whpx_gicv3_check(GICv3State *s)
39 {
40 }
41
42 static void whpx_gicv3_put(GICv3State *s)
43 {
44 whpx_gicv3_check(s);
45 }
46
47 static void whpx_gicv3_get(GICv3State *s)
48 {
49 }
50
51 static void whpx_gicv3_set_irq(void *opaque, int irq, int level)
52 {
53 struct whpx_state *whpx = &whpx_global;
54 GICv3State *s = opaque;
55 WHV_INTERRUPT_CONTROL interrupt_control = {
56 .InterruptControl.InterruptType = WHvArm64InterruptTypeFixed,
57 .RequestedVector = GIC_INTERNAL + irq,
58 .InterruptControl.Asserted = level
59 };
60
61 if (irq > s->num_irq) {
62 return;
63 }
64
65
66 whp_dispatch.WHvRequestInterrupt(whpx->partition, &interrupt_control,
67 sizeof(interrupt_control));
68 }
69
70 static void whpx_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
71 {
72 GICv3CPUState *c;
73
74 c = env->gicv3state;
75
76 c->icc_pmr_el1 = 0;
77 /*
78 * Architecturally the reset value of the ICC_BPR registers
79 * is UNKNOWN. We set them all to 0 here; when the kernel
80 * uses these values to program the ICH_VMCR_EL2 fields that
81 * determine the guest-visible ICC_BPR register values, the
82 * hardware's "writing a value less than the minimum sets
83 * the field to the minimum value" behaviour will result in
84 * them effectively resetting to the correct minimum value
85 * for the host GIC.
86 */
87 c->icc_bpr[GICV3_G0] = 0;
88 c->icc_bpr[GICV3_G1] = 0;
89 c->icc_bpr[GICV3_G1NS] = 0;
90
91 c->icc_sre_el1 = 0x7;
92 memset(c->icc_apr, 0, sizeof(c->icc_apr));
93 memset(c->icc_igrpen, 0, sizeof(c->icc_igrpen));
94 }
95
96 static void whpx_gicv3_reset_hold(Object *obj, ResetType type)
97 {
98 GICv3State *s = ARM_GICV3_COMMON(obj);
99 WHPXARMGICv3Class *kgc = WHPX_GICV3_GET_CLASS(s);
100
101 if (kgc->parent_phases.hold) {
102 kgc->parent_phases.hold(obj, type);
103 }
104
105 whpx_gicv3_put(s);
106 }
107
108
109 /*
110 * CPU interface registers of GIC needs to be reset on CPU reset.
111 * For the calling arm_gicv3_icc_reset() on CPU reset, we register
112 * below ARMCPRegInfo. As we reset the whole cpu interface under single
113 * register reset, we define only one register of CPU interface instead
114 * of defining all the registers.
115 */
116 static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
117 { .name = "ICC_CTLR_EL1", .state = ARM_CP_STATE_BOTH,
118 .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 4,
119 /*
120 * If ARM_CP_NOP is used, resetfn is not called,
121 * So ARM_CP_NO_RAW is appropriate type.
122 */
123 .type = ARM_CP_NO_RAW,
124 .access = PL1_RW,
125 .readfn = arm_cp_read_zero,
126 .writefn = arm_cp_write_ignore,
127 /*
128 * We hang the whole cpu interface reset routine off here
129 * rather than parcelling it out into one little function
130 * per register
131 */
132 .resetfn = whpx_gicv3_icc_reset,
133 },
134 };
135
136 static void whpx_set_reg(CPUState *cpu, WHV_REGISTER_NAME reg, WHV_REGISTER_VALUE val)
137 {
138 struct whpx_state *whpx = &whpx_global;
139 HRESULT hr;
140
141 hr = whp_dispatch.WHvSetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index,
142 &reg, 1, &val);
143
144 if (FAILED(hr)) {
145 error_report("WHPX: Failed to set register %08x, hr=%08lx", reg, hr);
146 }
147 }
148
149 static void whpx_gicv3_realize(DeviceState *dev, Error **errp)
150 {
151 ERRP_GUARD();
152 GICv3State *s = WHPX_GICV3(dev);
153 WHPXARMGICv3Class *kgc = WHPX_GICV3_GET_CLASS(s);
154 int i;
155
156 kgc->parent_realize(dev, errp);
157 if (*errp) {
158 return;
159 }
160
161 if (s->revision != 3) {
162 error_setg(errp, "unsupported GIC revision %d for platform GIC",
163 s->revision);
164 return;
165 }
166
167 if (s->security_extn) {
168 error_setg(errp, "the platform vGICv3 does not implement the "
169 "security extensions");
170 return;
171 }
172
173 if (s->nmi_support) {
174 error_setg(errp, "NMI is not supported with the platform GIC");
175 return;
176 }
177
178 if (s->nb_redist_regions > 1) {
179 error_setg(errp, "Multiple VGICv3 redistributor regions are not "
180 "supported by WHPX");
181 error_append_hint(errp, "A maximum of %d VCPUs can be used",
182 s->redist_region_count[0]);
183 return;
184 }
185
186 gicv3_init_irqs_and_mmio(s, whpx_gicv3_set_irq, NULL);
187
188 for (i = 0; i < s->num_cpu; i++) {
189 CPUState *cpu_state = qemu_get_cpu(i);
190 ARMCPU *cpu = ARM_CPU(cpu_state);
191 WHV_REGISTER_VALUE val = {.Reg64 = 0x080A0000 + (GICV3_REDIST_SIZE * i)};
192 whpx_set_reg(cpu_state, WHvArm64RegisterGicrBaseGpa, val);
193 define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
194 }
195
196 if (s->maint_irq) {
197 error_setg(errp, "Nested virtualisation not currently supported by WHPX.");
198 return;
199 }
200
201 error_setg(&s->migration_blocker,
202 "Live migration disabled because GIC state save/restore not supported on WHPX");
203 if (migrate_add_blocker(&s->migration_blocker, errp) < 0) {
204 error_report_err(*errp);
205 }
206 }
207
208 static void whpx_gicv3_class_init(ObjectClass *klass, const void *data)
209 {
210 DeviceClass *dc = DEVICE_CLASS(klass);
211 ResettableClass *rc = RESETTABLE_CLASS(klass);
212 ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass);
213 WHPXARMGICv3Class *kgc = WHPX_GICV3_CLASS(klass);
214
215 agcc->pre_save = whpx_gicv3_get;
216 agcc->post_load = whpx_gicv3_put;
217
218 device_class_set_parent_realize(dc, whpx_gicv3_realize,
219 &kgc->parent_realize);
220 resettable_class_set_parent_phases(rc, NULL, whpx_gicv3_reset_hold, NULL,
221 &kgc->parent_phases);
222 }
223
224 static const TypeInfo whpx_arm_gicv3_info = {
225 .name = TYPE_WHPX_GICV3,
226 .parent = TYPE_ARM_GICV3_COMMON,
227 .instance_size = sizeof(GICv3State),
228 .class_init = whpx_gicv3_class_init,
229 .class_size = sizeof(WHPXARMGICv3Class),
230 };
231
232 static void whpx_gicv3_register_types(void)
233 {
234 type_register_static(&whpx_arm_gicv3_info);
235 }
236
237 type_init(whpx_gicv3_register_types)