master
c 1,158 lines 38 KB
Raw
1 /*
2 * RISC-V APLIC (Advanced Platform Level Interrupt Controller)
3 *
4 * Copyright (c) 2021 Western Digital Corporation or its affiliates.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2 or later, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "qemu/osdep.h"
20 #include "qapi/error.h"
21 #include "qemu/log.h"
22 #include "qemu/module.h"
23 #include "qemu/error-report.h"
24 #include "qemu/bswap.h"
25 #include "system/address-spaces.h"
26 #include "hw/core/sysbus.h"
27 #include "hw/pci/msi.h"
28 #include "hw/core/boards.h"
29 #include "hw/core/qdev-properties.h"
30 #include "hw/intc/riscv_aplic.h"
31 #include "hw/core/irq.h"
32 #include "target/riscv/cpu.h"
33 #include "system/system.h"
34 #include "system/kvm.h"
35 #include "system/tcg.h"
36 #include "kvm/kvm_riscv.h"
37 #include "migration/vmstate.h"
38 #include "trace.h"
39
40 #define APLIC_MAX_IDC (1UL << 14)
41 #define APLIC_MAX_SOURCE 1024
42 #define APLIC_MIN_IPRIO_BITS 1
43 #define APLIC_MAX_IPRIO_BITS 8
44 #define APLIC_MAX_CHILDREN 1024
45
46 #define APLIC_DOMAINCFG 0x0000
47 #define APLIC_DOMAINCFG_RDONLY 0x80000000
48 #define APLIC_DOMAINCFG_IE (1 << 8)
49 #define APLIC_DOMAINCFG_DM (1 << 2)
50 #define APLIC_DOMAINCFG_BE (1 << 0)
51
52 #define APLIC_SOURCECFG_BASE 0x0004
53 #define APLIC_SOURCECFG_D (1 << 10)
54 #define APLIC_SOURCECFG_CHILDIDX_MASK 0x000003ff
55 #define APLIC_SOURCECFG_SM_MASK 0x00000007
56 #define APLIC_SOURCECFG_SM_INACTIVE 0x0
57 #define APLIC_SOURCECFG_SM_DETACH 0x1
58 #define APLIC_SOURCECFG_SM_EDGE_RISE 0x4
59 #define APLIC_SOURCECFG_SM_EDGE_FALL 0x5
60 #define APLIC_SOURCECFG_SM_LEVEL_HIGH 0x6
61 #define APLIC_SOURCECFG_SM_LEVEL_LOW 0x7
62
63 #define APLIC_MMSICFGADDR 0x1bc0
64 #define APLIC_MMSICFGADDRH 0x1bc4
65 #define APLIC_SMSICFGADDR 0x1bc8
66 #define APLIC_SMSICFGADDRH 0x1bcc
67
68 #define APLIC_xMSICFGADDRH_L (1UL << 31)
69 #define APLIC_xMSICFGADDRH_HHXS_MASK 0x1f
70 #define APLIC_xMSICFGADDRH_HHXS_SHIFT 24
71 #define APLIC_xMSICFGADDRH_LHXS_MASK 0x7
72 #define APLIC_xMSICFGADDRH_LHXS_SHIFT 20
73 #define APLIC_xMSICFGADDRH_HHXW_MASK 0x7
74 #define APLIC_xMSICFGADDRH_HHXW_SHIFT 16
75 #define APLIC_xMSICFGADDRH_LHXW_MASK 0xf
76 #define APLIC_xMSICFGADDRH_LHXW_SHIFT 12
77 #define APLIC_xMSICFGADDRH_BAPPN_MASK 0xfff
78
79 #define APLIC_xMSICFGADDR_PPN_SHIFT 12
80
81 #define APLIC_xMSICFGADDR_PPN_HART(__lhxs) \
82 ((1UL << (__lhxs)) - 1)
83
84 #define APLIC_xMSICFGADDR_PPN_LHX_MASK(__lhxw) \
85 ((1UL << (__lhxw)) - 1)
86 #define APLIC_xMSICFGADDR_PPN_LHX_SHIFT(__lhxs) \
87 ((__lhxs))
88 #define APLIC_xMSICFGADDR_PPN_LHX(__lhxw, __lhxs) \
89 (APLIC_xMSICFGADDR_PPN_LHX_MASK(__lhxw) << \
90 APLIC_xMSICFGADDR_PPN_LHX_SHIFT(__lhxs))
91
92 #define APLIC_xMSICFGADDR_PPN_HHX_MASK(__hhxw) \
93 ((1UL << (__hhxw)) - 1)
94 #define APLIC_xMSICFGADDR_PPN_HHX_SHIFT(__hhxs) \
95 ((__hhxs) + APLIC_xMSICFGADDR_PPN_SHIFT)
96 #define APLIC_xMSICFGADDR_PPN_HHX(__hhxw, __hhxs) \
97 (APLIC_xMSICFGADDR_PPN_HHX_MASK(__hhxw) << \
98 APLIC_xMSICFGADDR_PPN_HHX_SHIFT(__hhxs))
99
100 #define APLIC_MMSICFGADDRH_VALID_MASK \
101 (APLIC_xMSICFGADDRH_L | \
102 (APLIC_xMSICFGADDRH_HHXS_MASK << APLIC_xMSICFGADDRH_HHXS_SHIFT) | \
103 (APLIC_xMSICFGADDRH_LHXS_MASK << APLIC_xMSICFGADDRH_LHXS_SHIFT) | \
104 (APLIC_xMSICFGADDRH_HHXW_MASK << APLIC_xMSICFGADDRH_HHXW_SHIFT) | \
105 (APLIC_xMSICFGADDRH_LHXW_MASK << APLIC_xMSICFGADDRH_LHXW_SHIFT) | \
106 APLIC_xMSICFGADDRH_BAPPN_MASK)
107
108 #define APLIC_SMSICFGADDRH_VALID_MASK \
109 ((APLIC_xMSICFGADDRH_LHXS_MASK << APLIC_xMSICFGADDRH_LHXS_SHIFT) | \
110 APLIC_xMSICFGADDRH_BAPPN_MASK)
111
112 #define APLIC_SETIP_BASE 0x1c00
113 #define APLIC_SETIPNUM 0x1cdc
114
115 #define APLIC_CLRIP_BASE 0x1d00
116 #define APLIC_CLRIPNUM 0x1ddc
117
118 #define APLIC_SETIE_BASE 0x1e00
119 #define APLIC_SETIENUM 0x1edc
120
121 #define APLIC_CLRIE_BASE 0x1f00
122 #define APLIC_CLRIENUM 0x1fdc
123
124 #define APLIC_SETIPNUM_LE 0x2000
125 #define APLIC_SETIPNUM_BE 0x2004
126
127 #define APLIC_ISTATE_PENDING (1U << 0)
128 #define APLIC_ISTATE_ENABLED (1U << 1)
129 #define APLIC_ISTATE_ENPEND (APLIC_ISTATE_ENABLED | \
130 APLIC_ISTATE_PENDING)
131 #define APLIC_ISTATE_INPUT (1U << 8)
132
133 #define APLIC_GENMSI 0x3000
134
135 #define APLIC_TARGET_BASE 0x3004
136 #define APLIC_TARGET_HART_IDX_SHIFT 18
137 #define APLIC_TARGET_HART_IDX_MASK 0x3fff
138 #define APLIC_TARGET_GUEST_IDX_SHIFT 12
139 #define APLIC_TARGET_GUEST_IDX_MASK 0x3f
140 #define APLIC_TARGET_IPRIO_MASK 0xff
141 #define APLIC_TARGET_EIID_MASK 0x7ff
142
143 #define APLIC_IDC_BASE 0x4000
144 #define APLIC_IDC_SIZE 32
145
146 #define APLIC_IDC_IDELIVERY 0x00
147
148 #define APLIC_IDC_IFORCE 0x04
149
150 #define APLIC_IDC_ITHRESHOLD 0x08
151
152 #define APLIC_IDC_TOPI 0x18
153 #define APLIC_IDC_TOPI_ID_SHIFT 16
154 #define APLIC_IDC_TOPI_ID_MASK 0x3ff
155 #define APLIC_IDC_TOPI_PRIO_MASK 0xff
156
157 #define APLIC_IDC_CLAIMI 0x1c
158
159 /*
160 * KVM AIA only supports APLIC MSI, fallback to QEMU emulation if we want to use
161 * APLIC Wired.
162 */
163 bool riscv_is_kvm_aia_aplic_imsic(bool msimode)
164 {
165 return kvm_irqchip_in_kernel() && msimode;
166 }
167
168 bool riscv_use_emulated_aplic(bool msimode)
169 {
170 #ifdef CONFIG_KVM
171 if (tcg_enabled()) {
172 return true;
173 }
174
175 if (!riscv_is_kvm_aia_aplic_imsic(msimode)) {
176 return true;
177 }
178
179 return kvm_kernel_irqchip_split();
180 #else
181 return true;
182 #endif
183 }
184
185 void riscv_aplic_set_kvm_msicfgaddr(RISCVAPLICState *aplic, hwaddr addr)
186 {
187 #ifdef CONFIG_KVM
188 if (riscv_use_emulated_aplic(aplic->msimode)) {
189 addr >>= APLIC_xMSICFGADDR_PPN_SHIFT;
190 aplic->kvm_msicfgaddr = extract64(addr, 0, 32);
191 aplic->kvm_msicfgaddrH = extract64(addr, 32, 32) &
192 APLIC_MMSICFGADDRH_VALID_MASK;
193 }
194 #endif
195 }
196
197 /*
198 * APLIC target[i] must be read-only zero if the source i is inactive
199 * in this domain (delegated or SM == INACTIVE)
200 */
201 static inline bool riscv_aplic_source_active(RISCVAPLICState *aplic,
202 uint32_t irq)
203 {
204 uint32_t sc, sm;
205
206 if ((irq == 0) || (aplic->num_irqs <= irq)) {
207 return false;
208 }
209 sc = aplic->sourcecfg[irq];
210 if (sc & APLIC_SOURCECFG_D) {
211 return false;
212 }
213 sm = sc & APLIC_SOURCECFG_SM_MASK;
214 return sm != APLIC_SOURCECFG_SM_INACTIVE;
215 }
216
217 static bool riscv_aplic_irq_rectified_val(RISCVAPLICState *aplic,
218 uint32_t irq)
219 {
220 uint32_t sm, raw_input, irq_inverted;
221
222 if (!riscv_aplic_source_active(aplic, irq)) {
223 return false;
224 }
225
226 sm = aplic->sourcecfg[irq] & APLIC_SOURCECFG_SM_MASK;
227 raw_input = (aplic->state[irq] & APLIC_ISTATE_INPUT) ? 1 : 0;
228 irq_inverted = (sm == APLIC_SOURCECFG_SM_LEVEL_LOW ||
229 sm == APLIC_SOURCECFG_SM_EDGE_FALL) ? 1 : 0;
230
231 return !!(raw_input ^ irq_inverted);
232 }
233
234 static uint32_t riscv_aplic_read_input_word(RISCVAPLICState *aplic,
235 uint32_t word)
236 {
237 uint32_t i, irq, rectified_val, ret = 0;
238
239 for (i = 0; i < 32; i++) {
240 irq = word * 32 + i;
241
242 rectified_val = riscv_aplic_irq_rectified_val(aplic, irq);
243 ret |= rectified_val << i;
244 }
245
246 return ret;
247 }
248
249 static uint32_t riscv_aplic_read_pending_word(RISCVAPLICState *aplic,
250 uint32_t word)
251 {
252 uint32_t i, irq, ret = 0;
253
254 for (i = 0; i < 32; i++) {
255 irq = word * 32 + i;
256 if (!irq || aplic->num_irqs <= irq) {
257 continue;
258 }
259
260 ret |= ((aplic->state[irq] & APLIC_ISTATE_PENDING) ? 1 : 0) << i;
261 }
262
263 return ret;
264 }
265
266 static void riscv_aplic_set_pending_raw(RISCVAPLICState *aplic,
267 uint32_t irq, bool pending)
268 {
269 if (pending) {
270 aplic->state[irq] |= APLIC_ISTATE_PENDING;
271 } else {
272 aplic->state[irq] &= ~APLIC_ISTATE_PENDING;
273 }
274 }
275
276 static void riscv_aplic_set_pending(RISCVAPLICState *aplic,
277 uint32_t irq, bool pending)
278 {
279 uint32_t sm;
280
281 if (!riscv_aplic_source_active(aplic, irq)) {
282 return;
283 }
284
285 sm = aplic->sourcecfg[irq] & APLIC_SOURCECFG_SM_MASK;
286 if ((sm == APLIC_SOURCECFG_SM_LEVEL_HIGH) ||
287 (sm == APLIC_SOURCECFG_SM_LEVEL_LOW)) {
288 if (!aplic->msimode) {
289 return;
290 }
291 if (aplic->msimode && !pending) {
292 goto noskip_write_pending;
293 }
294 if ((aplic->state[irq] & APLIC_ISTATE_INPUT) &&
295 (sm == APLIC_SOURCECFG_SM_LEVEL_LOW)) {
296 return;
297 }
298 if (!(aplic->state[irq] & APLIC_ISTATE_INPUT) &&
299 (sm == APLIC_SOURCECFG_SM_LEVEL_HIGH)) {
300 return;
301 }
302 }
303
304 noskip_write_pending:
305 riscv_aplic_set_pending_raw(aplic, irq, pending);
306 }
307
308 static void riscv_aplic_set_pending_word(RISCVAPLICState *aplic,
309 uint32_t word, uint32_t value,
310 bool pending)
311 {
312 uint32_t i, irq;
313
314 for (i = 0; i < 32; i++) {
315 irq = word * 32 + i;
316 if (!irq || aplic->num_irqs <= irq) {
317 continue;
318 }
319
320 if (value & (1U << i)) {
321 riscv_aplic_set_pending(aplic, irq, pending);
322 }
323 }
324 }
325
326 static uint32_t riscv_aplic_read_enabled_word(RISCVAPLICState *aplic,
327 int word)
328 {
329 uint32_t i, irq, ret = 0;
330
331 for (i = 0; i < 32; i++) {
332 irq = word * 32 + i;
333 if (!irq || aplic->num_irqs <= irq) {
334 continue;
335 }
336
337 ret |= ((aplic->state[irq] & APLIC_ISTATE_ENABLED) ? 1 : 0) << i;
338 }
339
340 return ret;
341 }
342
343 static void riscv_aplic_set_enabled_raw(RISCVAPLICState *aplic,
344 uint32_t irq, bool enabled)
345 {
346 if (enabled) {
347 aplic->state[irq] |= APLIC_ISTATE_ENABLED;
348 } else {
349 aplic->state[irq] &= ~APLIC_ISTATE_ENABLED;
350 }
351 }
352
353 static void riscv_aplic_set_enabled(RISCVAPLICState *aplic,
354 uint32_t irq, bool enabled)
355 {
356 if (!riscv_aplic_source_active(aplic, irq)) {
357 return;
358 }
359
360 riscv_aplic_set_enabled_raw(aplic, irq, enabled);
361 }
362
363 static void riscv_aplic_set_enabled_word(RISCVAPLICState *aplic,
364 uint32_t word, uint32_t value,
365 bool enabled)
366 {
367 uint32_t i, irq;
368
369 for (i = 0; i < 32; i++) {
370 irq = word * 32 + i;
371 if (!irq || aplic->num_irqs <= irq) {
372 continue;
373 }
374
375 if (value & (1U << i)) {
376 riscv_aplic_set_enabled(aplic, irq, enabled);
377 }
378 }
379 }
380
381 static void riscv_aplic_msi_send(RISCVAPLICState *aplic,
382 uint32_t hart_idx, uint32_t guest_idx,
383 uint32_t eiid)
384 {
385 uint64_t addr;
386 MemTxResult result;
387 RISCVAPLICState *aplic_m;
388 uint32_t lhxs, lhxw, hhxs, hhxw, group_idx, msicfgaddr, msicfgaddrH;
389
390 aplic_m = aplic;
391
392 if (!aplic->kvm_splitmode) {
393 while (aplic_m && !aplic_m->mmode) {
394 aplic_m = aplic_m->parent;
395 }
396 if (!aplic_m) {
397 qemu_log_mask(LOG_GUEST_ERROR, "%s: m-level APLIC not found\n",
398 __func__);
399 return;
400 }
401 }
402
403 if (aplic->kvm_splitmode) {
404 msicfgaddr = aplic->kvm_msicfgaddr;
405 msicfgaddrH = ((uint64_t)aplic->kvm_msicfgaddrH << 32);
406 } else {
407 msicfgaddr = aplic_m->mmsicfgaddr;
408 msicfgaddrH = aplic_m->mmsicfgaddrH;
409 }
410
411 lhxs = (msicfgaddrH >> APLIC_xMSICFGADDRH_LHXS_SHIFT) &
412 APLIC_xMSICFGADDRH_LHXS_MASK;
413 lhxw = (msicfgaddrH >> APLIC_xMSICFGADDRH_LHXW_SHIFT) &
414 APLIC_xMSICFGADDRH_LHXW_MASK;
415 hhxs = (msicfgaddrH >> APLIC_xMSICFGADDRH_HHXS_SHIFT) &
416 APLIC_xMSICFGADDRH_HHXS_MASK;
417 hhxw = (msicfgaddrH >> APLIC_xMSICFGADDRH_HHXW_SHIFT) &
418 APLIC_xMSICFGADDRH_HHXW_MASK;
419
420 if (!aplic->kvm_splitmode && !aplic->mmode) {
421 msicfgaddrH = aplic_m->smsicfgaddrH;
422 msicfgaddr = aplic_m->smsicfgaddr;
423
424 lhxs = (msicfgaddrH >> APLIC_xMSICFGADDRH_LHXS_SHIFT) &
425 APLIC_xMSICFGADDRH_LHXS_MASK;
426 }
427
428 group_idx = hart_idx >> lhxw;
429
430 addr = msicfgaddr;
431 addr |= ((uint64_t)(msicfgaddrH & APLIC_xMSICFGADDRH_BAPPN_MASK)) << 32;
432 addr |= ((uint64_t)(group_idx & APLIC_xMSICFGADDR_PPN_HHX_MASK(hhxw))) <<
433 APLIC_xMSICFGADDR_PPN_HHX_SHIFT(hhxs);
434 addr |= ((uint64_t)(hart_idx & APLIC_xMSICFGADDR_PPN_LHX_MASK(lhxw))) <<
435 APLIC_xMSICFGADDR_PPN_LHX_SHIFT(lhxs);
436 addr |= (uint64_t)(guest_idx & APLIC_xMSICFGADDR_PPN_HART(lhxs));
437 addr <<= APLIC_xMSICFGADDR_PPN_SHIFT;
438
439 address_space_stl_le(&address_space_memory, addr,
440 eiid, MEMTXATTRS_UNSPECIFIED, &result);
441 if (result != MEMTX_OK) {
442 qemu_log_mask(LOG_GUEST_ERROR, "%s: MSI write failed for "
443 "hart_index=%d guest_index=%d eiid=%d\n",
444 __func__, hart_idx, guest_idx, eiid);
445 }
446 }
447
448 static void riscv_aplic_msi_irq_update(RISCVAPLICState *aplic, uint32_t irq)
449 {
450 uint32_t hart_idx, guest_idx, eiid;
451
452 if (!aplic->msimode || (aplic->num_irqs <= irq) ||
453 !(aplic->domaincfg & APLIC_DOMAINCFG_IE)) {
454 return;
455 }
456
457 if ((aplic->state[irq] & APLIC_ISTATE_ENPEND) != APLIC_ISTATE_ENPEND) {
458 return;
459 }
460
461 riscv_aplic_set_pending_raw(aplic, irq, false);
462
463 hart_idx = aplic->target[irq] >> APLIC_TARGET_HART_IDX_SHIFT;
464 hart_idx &= APLIC_TARGET_HART_IDX_MASK;
465 if (aplic->mmode) {
466 /* M-level APLIC ignores guest_index */
467 guest_idx = 0;
468 } else {
469 guest_idx = aplic->target[irq] >> APLIC_TARGET_GUEST_IDX_SHIFT;
470 guest_idx &= APLIC_TARGET_GUEST_IDX_MASK;
471 }
472 eiid = aplic->target[irq] & APLIC_TARGET_EIID_MASK;
473 riscv_aplic_msi_send(aplic, hart_idx, guest_idx, eiid);
474 }
475
476 static uint32_t riscv_aplic_idc_topi(RISCVAPLICState *aplic, uint32_t idc)
477 {
478 uint32_t best_irq, best_iprio;
479 uint32_t irq, iprio, ihartidx, ithres;
480
481 if (aplic->num_harts <= idc) {
482 return 0;
483 }
484
485 ithres = aplic->ithreshold[idc];
486 best_irq = best_iprio = UINT32_MAX;
487 for (irq = 1; irq < aplic->num_irqs; irq++) {
488 if ((aplic->state[irq] & APLIC_ISTATE_ENPEND) !=
489 APLIC_ISTATE_ENPEND) {
490 continue;
491 }
492
493 ihartidx = aplic->target[irq] >> APLIC_TARGET_HART_IDX_SHIFT;
494 ihartidx &= APLIC_TARGET_HART_IDX_MASK;
495 if (ihartidx != idc) {
496 continue;
497 }
498
499 iprio = aplic->target[irq] & aplic->iprio_mask;
500 if (ithres && iprio >= ithres) {
501 continue;
502 }
503
504 if (iprio < best_iprio) {
505 best_irq = irq;
506 best_iprio = iprio;
507 }
508 }
509
510 if (best_irq < aplic->num_irqs && best_iprio <= aplic->iprio_mask) {
511 return (best_irq << APLIC_IDC_TOPI_ID_SHIFT) | best_iprio;
512 }
513
514 return 0;
515 }
516
517 static void riscv_aplic_idc_update(RISCVAPLICState *aplic, uint32_t idc)
518 {
519 uint32_t topi;
520
521 if (aplic->msimode || aplic->num_harts <= idc) {
522 return;
523 }
524
525 topi = riscv_aplic_idc_topi(aplic, idc);
526 if ((aplic->domaincfg & APLIC_DOMAINCFG_IE) &&
527 aplic->idelivery[idc] &&
528 (aplic->iforce[idc] || topi)) {
529 qemu_irq_raise(aplic->external_irqs[idc]);
530 } else {
531 qemu_irq_lower(aplic->external_irqs[idc]);
532 }
533 }
534
535 static uint32_t riscv_aplic_idc_claimi(RISCVAPLICState *aplic, uint32_t idc)
536 {
537 uint32_t irq, state, sm, topi = riscv_aplic_idc_topi(aplic, idc);
538
539 if (!topi) {
540 aplic->iforce[idc] = 0;
541 riscv_aplic_idc_update(aplic, idc);
542 return 0;
543 }
544
545 irq = (topi >> APLIC_IDC_TOPI_ID_SHIFT) & APLIC_IDC_TOPI_ID_MASK;
546 sm = aplic->sourcecfg[irq] & APLIC_SOURCECFG_SM_MASK;
547 state = aplic->state[irq];
548 riscv_aplic_set_pending_raw(aplic, irq, false);
549 if ((sm == APLIC_SOURCECFG_SM_LEVEL_HIGH) &&
550 (state & APLIC_ISTATE_INPUT)) {
551 riscv_aplic_set_pending_raw(aplic, irq, true);
552 } else if ((sm == APLIC_SOURCECFG_SM_LEVEL_LOW) &&
553 !(state & APLIC_ISTATE_INPUT)) {
554 riscv_aplic_set_pending_raw(aplic, irq, true);
555 }
556 riscv_aplic_idc_update(aplic, idc);
557
558 return topi;
559 }
560
561 static void riscv_aplic_request(void *opaque, int irq, int level)
562 {
563 bool update = false;
564 RISCVAPLICState *aplic = opaque;
565 uint32_t sourcecfg, childidx, state, idc;
566
567 assert((0 < irq) && (irq < aplic->num_irqs));
568
569 sourcecfg = aplic->sourcecfg[irq];
570 if (sourcecfg & APLIC_SOURCECFG_D) {
571 childidx = sourcecfg & APLIC_SOURCECFG_CHILDIDX_MASK;
572 if (childidx < aplic->num_children) {
573 riscv_aplic_request(aplic->children[childidx], irq, level);
574 }
575 return;
576 }
577
578 state = aplic->state[irq];
579 switch (sourcecfg & APLIC_SOURCECFG_SM_MASK) {
580 case APLIC_SOURCECFG_SM_EDGE_RISE:
581 if ((level > 0) && !(state & APLIC_ISTATE_INPUT) &&
582 !(state & APLIC_ISTATE_PENDING)) {
583 riscv_aplic_set_pending_raw(aplic, irq, true);
584 update = true;
585 }
586 break;
587 case APLIC_SOURCECFG_SM_EDGE_FALL:
588 if ((level <= 0) && (state & APLIC_ISTATE_INPUT) &&
589 !(state & APLIC_ISTATE_PENDING)) {
590 riscv_aplic_set_pending_raw(aplic, irq, true);
591 update = true;
592 }
593 break;
594 case APLIC_SOURCECFG_SM_LEVEL_HIGH:
595 if ((level > 0) != !!(state & APLIC_ISTATE_PENDING)) {
596 riscv_aplic_set_pending_raw(aplic, irq, level > 0);
597 update = true;
598 }
599 break;
600 case APLIC_SOURCECFG_SM_LEVEL_LOW:
601 if ((level <= 0) != !!(state & APLIC_ISTATE_PENDING)) {
602 riscv_aplic_set_pending_raw(aplic, irq, level <= 0);
603 update = true;
604 }
605 break;
606 default:
607 break;
608 }
609
610 if (level <= 0) {
611 aplic->state[irq] &= ~APLIC_ISTATE_INPUT;
612 } else {
613 aplic->state[irq] |= APLIC_ISTATE_INPUT;
614 }
615
616 if (update) {
617 if (aplic->msimode) {
618 riscv_aplic_msi_irq_update(aplic, irq);
619 } else {
620 idc = aplic->target[irq] >> APLIC_TARGET_HART_IDX_SHIFT;
621 idc &= APLIC_TARGET_HART_IDX_MASK;
622 riscv_aplic_idc_update(aplic, idc);
623 }
624 }
625 }
626
627 static uint64_t riscv_aplic_read(void *opaque, hwaddr addr, unsigned size)
628 {
629 uint32_t irq, word, idc;
630 uint64_t val = 0;
631 RISCVAPLICState *aplic = opaque;
632
633 /* Reads must be 4 byte words */
634 if ((addr & 0x3) != 0) {
635 goto err;
636 }
637
638 if (addr == APLIC_DOMAINCFG) {
639 val = APLIC_DOMAINCFG_RDONLY | aplic->domaincfg |
640 (aplic->msimode ? APLIC_DOMAINCFG_DM : 0);
641 } else if ((APLIC_SOURCECFG_BASE <= addr) &&
642 (addr < (APLIC_SOURCECFG_BASE + (aplic->num_irqs - 1) * 4))) {
643 irq = ((addr - APLIC_SOURCECFG_BASE) >> 2) + 1;
644 val = aplic->sourcecfg[irq];
645 } else if (aplic->mmode && aplic->msimode &&
646 (addr == APLIC_MMSICFGADDR)) {
647 val = aplic->mmsicfgaddr;
648 } else if (aplic->mmode && aplic->msimode &&
649 (addr == APLIC_MMSICFGADDRH)) {
650 val = aplic->mmsicfgaddrH;
651 } else if (aplic->mmode && aplic->msimode &&
652 (addr == APLIC_SMSICFGADDR)) {
653 /*
654 * Registers SMSICFGADDR and SMSICFGADDRH are implemented only if:
655 * (a) the interrupt domain is at machine level
656 * (b) the domain's harts implement supervisor mode
657 * (c) the domain has one or more child supervisor-level domains
658 * that support MSI delivery mode (domaincfg.DM is not read-
659 * only zero in at least one of the supervisor-level child
660 * domains).
661 */
662 val = (aplic->num_children) ? aplic->smsicfgaddr : 0;
663 } else if (aplic->mmode && aplic->msimode &&
664 (addr == APLIC_SMSICFGADDRH)) {
665 val = (aplic->num_children) ? aplic->smsicfgaddrH : 0;
666 } else if ((APLIC_SETIP_BASE <= addr) &&
667 (addr < (APLIC_SETIP_BASE + aplic->bitfield_words * 4))) {
668 word = (addr - APLIC_SETIP_BASE) >> 2;
669 val = riscv_aplic_read_pending_word(aplic, word);
670 } else if (addr == APLIC_SETIPNUM) {
671 val = 0;
672 } else if ((APLIC_CLRIP_BASE <= addr) &&
673 (addr < (APLIC_CLRIP_BASE + aplic->bitfield_words * 4))) {
674 word = (addr - APLIC_CLRIP_BASE) >> 2;
675 val = riscv_aplic_read_input_word(aplic, word);
676 } else if (addr == APLIC_CLRIPNUM) {
677 val = 0;
678 } else if ((APLIC_SETIE_BASE <= addr) &&
679 (addr < (APLIC_SETIE_BASE + aplic->bitfield_words * 4))) {
680 word = (addr - APLIC_SETIE_BASE) >> 2;
681 val = riscv_aplic_read_enabled_word(aplic, word);
682 } else if (addr == APLIC_SETIENUM) {
683 val = 0;
684 } else if ((APLIC_CLRIE_BASE <= addr) &&
685 (addr < (APLIC_CLRIE_BASE + aplic->bitfield_words * 4))) {
686 val = 0;
687 } else if (addr == APLIC_CLRIENUM) {
688 val = 0;
689 } else if (addr == APLIC_SETIPNUM_LE) {
690 val = 0;
691 } else if (addr == APLIC_SETIPNUM_BE) {
692 val = 0;
693 } else if (addr == APLIC_GENMSI) {
694 val = (aplic->msimode) ? aplic->genmsi : 0;
695 } else if ((APLIC_TARGET_BASE <= addr) &&
696 (addr < (APLIC_TARGET_BASE + (aplic->num_irqs - 1) * 4))) {
697 irq = ((addr - APLIC_TARGET_BASE) >> 2) + 1;
698 if (!riscv_aplic_source_active(aplic, irq)) {
699 val = 0;
700 } else {
701 val = aplic->target[irq];
702 }
703 } else if (!aplic->msimode && (APLIC_IDC_BASE <= addr) &&
704 (addr < (APLIC_IDC_BASE + aplic->num_harts * APLIC_IDC_SIZE))) {
705 idc = (addr - APLIC_IDC_BASE) / APLIC_IDC_SIZE;
706 switch (addr - (APLIC_IDC_BASE + idc * APLIC_IDC_SIZE)) {
707 case APLIC_IDC_IDELIVERY:
708 val = aplic->idelivery[idc];
709 break;
710 case APLIC_IDC_IFORCE:
711 val = aplic->iforce[idc];
712 break;
713 case APLIC_IDC_ITHRESHOLD:
714 val = aplic->ithreshold[idc];
715 break;
716 case APLIC_IDC_TOPI:
717 val = riscv_aplic_idc_topi(aplic, idc);
718 break;
719 case APLIC_IDC_CLAIMI:
720 val = riscv_aplic_idc_claimi(aplic, idc);
721 break;
722 default:
723 goto err;
724 };
725 }
726
727 trace_riscv_aplic_read(addr, size, val);
728 return val;
729
730 err:
731 qemu_log_mask(LOG_GUEST_ERROR,
732 "%s: Invalid register read 0x%" HWADDR_PRIx "\n",
733 __func__, addr);
734 return 0;
735 }
736
737 static void riscv_aplic_write(void *opaque, hwaddr addr, uint64_t value,
738 unsigned size)
739 {
740 RISCVAPLICState *aplic = opaque;
741 uint32_t irq, word, idc = UINT32_MAX;
742
743 /* Writes must be 4 byte words */
744 if ((addr & 0x3) != 0) {
745 goto err;
746 }
747
748 trace_riscv_aplic_write(addr, size, value);
749
750 if (addr == APLIC_DOMAINCFG) {
751 /* Only IE bit writable at the moment */
752 value &= APLIC_DOMAINCFG_IE;
753 aplic->domaincfg = value;
754 } else if ((APLIC_SOURCECFG_BASE <= addr) &&
755 (addr < (APLIC_SOURCECFG_BASE + (aplic->num_irqs - 1) * 4))) {
756 irq = ((addr - APLIC_SOURCECFG_BASE) >> 2) + 1;
757 if (!aplic->num_children && (value & APLIC_SOURCECFG_D)) {
758 value = 0;
759 }
760 if (value & APLIC_SOURCECFG_D) {
761 value &= (APLIC_SOURCECFG_D | APLIC_SOURCECFG_CHILDIDX_MASK);
762 } else {
763 value &= (APLIC_SOURCECFG_D | APLIC_SOURCECFG_SM_MASK);
764 }
765 aplic->sourcecfg[irq] = value;
766 if ((aplic->sourcecfg[irq] & APLIC_SOURCECFG_D) ||
767 (aplic->sourcecfg[irq] == 0)) {
768 riscv_aplic_set_pending_raw(aplic, irq, false);
769 riscv_aplic_set_enabled_raw(aplic, irq, false);
770 } else {
771 if (riscv_aplic_irq_rectified_val(aplic, irq)) {
772 riscv_aplic_set_pending_raw(aplic, irq, true);
773 }
774 }
775 } else if (aplic->mmode && aplic->msimode &&
776 (addr == APLIC_MMSICFGADDR)) {
777 if (!(aplic->mmsicfgaddrH & APLIC_xMSICFGADDRH_L)) {
778 aplic->mmsicfgaddr = value;
779 }
780 } else if (aplic->mmode && aplic->msimode &&
781 (addr == APLIC_MMSICFGADDRH)) {
782 if (!(aplic->mmsicfgaddrH & APLIC_xMSICFGADDRH_L)) {
783 aplic->mmsicfgaddrH = value & APLIC_MMSICFGADDRH_VALID_MASK;
784 }
785 } else if (aplic->mmode && aplic->msimode &&
786 (addr == APLIC_SMSICFGADDR)) {
787 /*
788 * Registers SMSICFGADDR and SMSICFGADDRH are implemented only if:
789 * (a) the interrupt domain is at machine level
790 * (b) the domain's harts implement supervisor mode
791 * (c) the domain has one or more child supervisor-level domains
792 * that support MSI delivery mode (domaincfg.DM is not read-
793 * only zero in at least one of the supervisor-level child
794 * domains).
795 */
796 if (aplic->num_children &&
797 !(aplic->mmsicfgaddrH & APLIC_xMSICFGADDRH_L)) {
798 aplic->smsicfgaddr = value;
799 }
800 } else if (aplic->mmode && aplic->msimode &&
801 (addr == APLIC_SMSICFGADDRH)) {
802 if (aplic->num_children &&
803 !(aplic->mmsicfgaddrH & APLIC_xMSICFGADDRH_L)) {
804 aplic->smsicfgaddrH = value & APLIC_SMSICFGADDRH_VALID_MASK;
805 }
806 } else if ((APLIC_SETIP_BASE <= addr) &&
807 (addr < (APLIC_SETIP_BASE + aplic->bitfield_words * 4))) {
808 word = (addr - APLIC_SETIP_BASE) >> 2;
809 riscv_aplic_set_pending_word(aplic, word, value, true);
810 } else if (addr == APLIC_SETIPNUM) {
811 riscv_aplic_set_pending(aplic, value, true);
812 } else if ((APLIC_CLRIP_BASE <= addr) &&
813 (addr < (APLIC_CLRIP_BASE + aplic->bitfield_words * 4))) {
814 word = (addr - APLIC_CLRIP_BASE) >> 2;
815 riscv_aplic_set_pending_word(aplic, word, value, false);
816 } else if (addr == APLIC_CLRIPNUM) {
817 riscv_aplic_set_pending(aplic, value, false);
818 } else if ((APLIC_SETIE_BASE <= addr) &&
819 (addr < (APLIC_SETIE_BASE + aplic->bitfield_words * 4))) {
820 word = (addr - APLIC_SETIE_BASE) >> 2;
821 riscv_aplic_set_enabled_word(aplic, word, value, true);
822 } else if (addr == APLIC_SETIENUM) {
823 riscv_aplic_set_enabled(aplic, value, true);
824 } else if ((APLIC_CLRIE_BASE <= addr) &&
825 (addr < (APLIC_CLRIE_BASE + aplic->bitfield_words * 4))) {
826 word = (addr - APLIC_CLRIE_BASE) >> 2;
827 riscv_aplic_set_enabled_word(aplic, word, value, false);
828 } else if (addr == APLIC_CLRIENUM) {
829 riscv_aplic_set_enabled(aplic, value, false);
830 } else if (addr == APLIC_SETIPNUM_LE) {
831 riscv_aplic_set_pending(aplic, value, true);
832 } else if (addr == APLIC_SETIPNUM_BE) {
833 riscv_aplic_set_pending(aplic, bswap32(value), true);
834 } else if (addr == APLIC_GENMSI) {
835 if (aplic->msimode) {
836 aplic->genmsi = value & ~(APLIC_TARGET_GUEST_IDX_MASK <<
837 APLIC_TARGET_GUEST_IDX_SHIFT);
838 riscv_aplic_msi_send(aplic,
839 value >> APLIC_TARGET_HART_IDX_SHIFT,
840 0,
841 value & APLIC_TARGET_EIID_MASK);
842 }
843 } else if ((APLIC_TARGET_BASE <= addr) &&
844 (addr < (APLIC_TARGET_BASE + (aplic->num_irqs - 1) * 4))) {
845 irq = ((addr - APLIC_TARGET_BASE) >> 2) + 1;
846 if (!riscv_aplic_source_active(aplic, irq)) {
847 return;
848 }
849 if (aplic->msimode) {
850 aplic->target[irq] = value;
851 } else {
852 aplic->target[irq] = (value & ~APLIC_TARGET_IPRIO_MASK) |
853 ((value & aplic->iprio_mask) ?
854 (value & aplic->iprio_mask) : 1);
855 }
856 } else if (!aplic->msimode && (APLIC_IDC_BASE <= addr) &&
857 (addr < (APLIC_IDC_BASE + aplic->num_harts * APLIC_IDC_SIZE))) {
858 idc = (addr - APLIC_IDC_BASE) / APLIC_IDC_SIZE;
859 switch (addr - (APLIC_IDC_BASE + idc * APLIC_IDC_SIZE)) {
860 case APLIC_IDC_IDELIVERY:
861 aplic->idelivery[idc] = value & 0x1;
862 break;
863 case APLIC_IDC_IFORCE:
864 aplic->iforce[idc] = value & 0x1;
865 break;
866 case APLIC_IDC_ITHRESHOLD:
867 aplic->ithreshold[idc] = value & aplic->iprio_mask;
868 break;
869 default:
870 goto err;
871 };
872 } else {
873 goto err;
874 }
875
876 if (aplic->msimode) {
877 for (irq = 1; irq < aplic->num_irqs; irq++) {
878 riscv_aplic_msi_irq_update(aplic, irq);
879 }
880 } else {
881 if (idc == UINT32_MAX) {
882 for (idc = 0; idc < aplic->num_harts; idc++) {
883 riscv_aplic_idc_update(aplic, idc);
884 }
885 } else {
886 riscv_aplic_idc_update(aplic, idc);
887 }
888 }
889
890 return;
891
892 err:
893 qemu_log_mask(LOG_GUEST_ERROR,
894 "%s: Invalid register write 0x%" HWADDR_PRIx "\n",
895 __func__, addr);
896 }
897
898 static const MemoryRegionOps riscv_aplic_ops = {
899 .read = riscv_aplic_read,
900 .write = riscv_aplic_write,
901 .endianness = DEVICE_LITTLE_ENDIAN,
902 .valid = {
903 .min_access_size = 4,
904 .max_access_size = 4
905 }
906 };
907
908 static void riscv_aplic_reset_enter(Object *obj, ResetType type)
909 {
910 RISCVAPLICState *aplic = RISCV_APLIC(obj);
911 int i;
912
913 if (!riscv_use_emulated_aplic(aplic->msimode)) {
914 return;
915 }
916
917 aplic->domaincfg = 0;
918 memset(aplic->sourcecfg, 0, sizeof(uint32_t) * aplic->num_irqs);
919 memset(aplic->target, 0, sizeof(uint32_t) * aplic->num_irqs);
920 if (!aplic->msimode) {
921 for (i = 0; i < aplic->num_irqs; i++) {
922 aplic->target[i] = 1;
923 }
924 }
925
926 for (i = 0; i < aplic->num_irqs ; i++) {
927 riscv_aplic_set_enabled_raw(aplic, i, false);
928 }
929
930 /* Need to unlock [ms]msicfgaddrh.L */
931 aplic->mmsicfgaddr = 0;
932 aplic->mmsicfgaddrH = 0;
933 aplic->smsicfgaddr = 0;
934 aplic->smsicfgaddrH = 0;
935
936 if (!aplic->msimode) {
937 /* Reset IDC registers only in non-MSI mode */
938 for (i = 0; i < aplic->num_harts; i++) {
939 aplic->idelivery[i] = 0;
940 aplic->iforce[i] = 0;
941 aplic->ithreshold[i] = 0;
942 }
943
944 for (i = 0; i < aplic->num_harts; i++) {
945 qemu_irq_lower(aplic->external_irqs[i]);
946 }
947 }
948 }
949
950 static void riscv_aplic_realize(DeviceState *dev, Error **errp)
951 {
952 uint32_t i;
953 RISCVAPLICState *aplic = RISCV_APLIC(dev);
954
955 if (riscv_use_emulated_aplic(aplic->msimode)) {
956 /* Create output IRQ lines for non-MSI mode */
957 if (!aplic->msimode) {
958 /* Claim the CPU interrupt to be triggered by this APLIC */
959 for (i = 0; i < aplic->num_harts; i++) {
960 CPUState *temp = cpu_by_arch_id(aplic->hartid_base + i);
961 if (temp == NULL) {
962 /* Valid for sparse hart layouts - skip this hart ID */
963 continue;
964 }
965 RISCVCPU *cpu = RISCV_CPU(temp);
966 if (riscv_cpu_claim_interrupts(cpu,
967 (aplic->mmode) ? MIP_MEIP : MIP_SEIP) < 0) {
968 error_report("%s already claimed",
969 (aplic->mmode) ? "MEIP" : "SEIP");
970 exit(1);
971 }
972 }
973
974 aplic->external_irqs = g_malloc(sizeof(qemu_irq) *
975 aplic->num_harts);
976 qdev_init_gpio_out(dev, aplic->external_irqs, aplic->num_harts);
977 }
978
979 aplic->bitfield_words = (aplic->num_irqs + 31) >> 5;
980 aplic->sourcecfg = g_new0(uint32_t, aplic->num_irqs);
981 aplic->state = g_new0(uint32_t, aplic->num_irqs);
982 aplic->target = g_new0(uint32_t, aplic->num_irqs);
983 aplic->idelivery = g_new0(uint32_t, aplic->num_harts);
984 aplic->iforce = g_new0(uint32_t, aplic->num_harts);
985 aplic->ithreshold = g_new0(uint32_t, aplic->num_harts);
986
987 memory_region_init_io(&aplic->mmio, OBJECT(dev), &riscv_aplic_ops,
988 aplic, TYPE_RISCV_APLIC, aplic->aperture_size);
989 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &aplic->mmio);
990
991 if (kvm_enabled()) {
992 aplic->kvm_splitmode = true;
993 }
994 }
995
996 /*
997 * Only root APLICs have hardware IRQ lines. All non-root APLICs
998 * have IRQ lines delegated by their parent APLIC.
999 */
1000 if (!aplic->parent) {
1001 if (kvm_enabled() && !riscv_use_emulated_aplic(aplic->msimode)) {
1002 qdev_init_gpio_in(dev, riscv_kvm_aplic_request, aplic->num_irqs);
1003 } else {
1004 qdev_init_gpio_in(dev, riscv_aplic_request, aplic->num_irqs);
1005 }
1006 }
1007
1008 msi_nonbroken = true;
1009 }
1010
1011 static const Property riscv_aplic_properties[] = {
1012 DEFINE_PROP_UINT32("aperture-size", RISCVAPLICState, aperture_size, 0),
1013 DEFINE_PROP_UINT32("hartid-base", RISCVAPLICState, hartid_base, 0),
1014 DEFINE_PROP_UINT32("num-harts", RISCVAPLICState, num_harts, 0),
1015 DEFINE_PROP_UINT32("iprio-mask", RISCVAPLICState, iprio_mask, 0),
1016 DEFINE_PROP_UINT32("num-irqs", RISCVAPLICState, num_irqs, 0),
1017 DEFINE_PROP_BOOL("msimode", RISCVAPLICState, msimode, 0),
1018 DEFINE_PROP_BOOL("mmode", RISCVAPLICState, mmode, 0),
1019 };
1020
1021 static bool riscv_aplic_state_needed(void *opaque)
1022 {
1023 RISCVAPLICState *aplic = opaque;
1024
1025 return riscv_use_emulated_aplic(aplic->msimode);
1026 }
1027
1028 static const VMStateDescription vmstate_riscv_aplic = {
1029 .name = "riscv_aplic",
1030 .version_id = 3,
1031 .minimum_version_id = 3,
1032 .needed = riscv_aplic_state_needed,
1033 .fields = (const VMStateField[]) {
1034 VMSTATE_UINT32(domaincfg, RISCVAPLICState),
1035 VMSTATE_UINT32(mmsicfgaddr, RISCVAPLICState),
1036 VMSTATE_UINT32(mmsicfgaddrH, RISCVAPLICState),
1037 VMSTATE_UINT32(smsicfgaddr, RISCVAPLICState),
1038 VMSTATE_UINT32(smsicfgaddrH, RISCVAPLICState),
1039 VMSTATE_UINT32(genmsi, RISCVAPLICState),
1040 VMSTATE_UINT32(kvm_msicfgaddr, RISCVAPLICState),
1041 VMSTATE_UINT32(kvm_msicfgaddrH, RISCVAPLICState),
1042 VMSTATE_VARRAY_UINT32(sourcecfg, RISCVAPLICState,
1043 num_irqs, 0,
1044 vmstate_info_uint32, uint32_t),
1045 VMSTATE_VARRAY_UINT32(state, RISCVAPLICState,
1046 num_irqs, 0,
1047 vmstate_info_uint32, uint32_t),
1048 VMSTATE_VARRAY_UINT32(target, RISCVAPLICState,
1049 num_irqs, 0,
1050 vmstate_info_uint32, uint32_t),
1051 VMSTATE_VARRAY_UINT32(idelivery, RISCVAPLICState,
1052 num_harts, 0,
1053 vmstate_info_uint32, uint32_t),
1054 VMSTATE_VARRAY_UINT32(iforce, RISCVAPLICState,
1055 num_harts, 0,
1056 vmstate_info_uint32, uint32_t),
1057 VMSTATE_VARRAY_UINT32(ithreshold, RISCVAPLICState,
1058 num_harts, 0,
1059 vmstate_info_uint32, uint32_t),
1060 VMSTATE_END_OF_LIST()
1061 }
1062 };
1063
1064 static void riscv_aplic_class_init(ObjectClass *klass, const void *data)
1065 {
1066 DeviceClass *dc = DEVICE_CLASS(klass);
1067 ResettableClass *rc = RESETTABLE_CLASS(klass);
1068
1069 device_class_set_props(dc, riscv_aplic_properties);
1070 dc->realize = riscv_aplic_realize;
1071 rc->phases.enter = riscv_aplic_reset_enter;
1072 dc->vmsd = &vmstate_riscv_aplic;
1073 }
1074
1075 static const TypeInfo riscv_aplic_info = {
1076 .name = TYPE_RISCV_APLIC,
1077 .parent = TYPE_SYS_BUS_DEVICE,
1078 .instance_size = sizeof(RISCVAPLICState),
1079 .class_init = riscv_aplic_class_init,
1080 };
1081
1082 static void riscv_aplic_register_types(void)
1083 {
1084 type_register_static(&riscv_aplic_info);
1085 }
1086
1087 type_init(riscv_aplic_register_types)
1088
1089 /*
1090 * Add a APLIC device to another APLIC device as child for
1091 * interrupt delegation.
1092 */
1093 void riscv_aplic_add_child(DeviceState *parent, DeviceState *child)
1094 {
1095 RISCVAPLICState *caplic, *paplic;
1096
1097 assert(parent && child);
1098 caplic = RISCV_APLIC(child);
1099 paplic = RISCV_APLIC(parent);
1100
1101 assert(paplic->num_irqs == caplic->num_irqs);
1102 assert(paplic->num_children <= QEMU_APLIC_MAX_CHILDREN);
1103
1104 caplic->parent = paplic;
1105 paplic->children[paplic->num_children] = caplic;
1106 paplic->num_children++;
1107 }
1108
1109 /*
1110 * Create APLIC device.
1111 */
1112 DeviceState *riscv_aplic_create(hwaddr addr, hwaddr size,
1113 uint32_t hartid_base, uint32_t num_harts, uint32_t num_sources,
1114 uint32_t iprio_bits, bool msimode, bool mmode, DeviceState *parent)
1115 {
1116 DeviceState *dev = qdev_new(TYPE_RISCV_APLIC);
1117 uint32_t i;
1118
1119 assert(num_harts < APLIC_MAX_IDC);
1120 assert((APLIC_IDC_BASE + (num_harts * APLIC_IDC_SIZE)) <= size);
1121 assert(num_sources < APLIC_MAX_SOURCE);
1122 assert(APLIC_MIN_IPRIO_BITS <= iprio_bits);
1123 assert(iprio_bits <= APLIC_MAX_IPRIO_BITS);
1124
1125 qdev_prop_set_uint32(dev, "aperture-size", size);
1126 qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
1127 qdev_prop_set_uint32(dev, "num-harts", num_harts);
1128 qdev_prop_set_uint32(dev, "iprio-mask", ((1U << iprio_bits) - 1));
1129 qdev_prop_set_uint32(dev, "num-irqs", num_sources + 1);
1130 qdev_prop_set_bit(dev, "msimode", msimode);
1131 qdev_prop_set_bit(dev, "mmode", mmode);
1132
1133 if (parent) {
1134 riscv_aplic_add_child(parent, dev);
1135 }
1136
1137 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
1138
1139 if (riscv_use_emulated_aplic(msimode)) {
1140 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
1141
1142 if (!msimode) {
1143 for (i = 0; i < num_harts; i++) {
1144 CPUState *cpu = cpu_by_arch_id(hartid_base + i);
1145 if (cpu == NULL) {
1146 /* Valid for sparse hart layouts - skip this hart ID */
1147 continue;
1148 }
1149
1150 qdev_connect_gpio_out_named(dev, NULL, i,
1151 qdev_get_gpio_in(DEVICE(cpu),
1152 (mmode) ? IRQ_M_EXT : IRQ_S_EXT));
1153 }
1154 }
1155 }
1156
1157 return dev;
1158 }