2 * RISC-V APLIC (Advanced Platform Level Interrupt Controller)
4 * Copyright (c) 2021 Western Digital Corporation or its affiliates.
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.
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
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/>.
19 #include "qemu/osdep.h"
20 #include "qapi/error.h"
22 #include "qemu/module.h"
23 #include "qemu/error-report.h"
24 #include "qemu/bswap.h"
25 #include "exec/address-spaces.h"
26 #include "hw/sysbus.h"
27 #include "hw/pci/msi.h"
28 #include "hw/boards.h"
29 #include "hw/qdev-properties.h"
30 #include "hw/intc/riscv_aplic.h"
32 #include "target/riscv/cpu.h"
33 #include "sysemu/sysemu.h"
34 #include "migration/vmstate.h"
36 #define APLIC_MAX_IDC (1UL << 14)
37 #define APLIC_MAX_SOURCE 1024
38 #define APLIC_MIN_IPRIO_BITS 1
39 #define APLIC_MAX_IPRIO_BITS 8
40 #define APLIC_MAX_CHILDREN 1024
42 #define APLIC_DOMAINCFG 0x0000
43 #define APLIC_DOMAINCFG_RDONLY 0x80000000
44 #define APLIC_DOMAINCFG_IE (1 << 8)
45 #define APLIC_DOMAINCFG_DM (1 << 2)
46 #define APLIC_DOMAINCFG_BE (1 << 0)
48 #define APLIC_SOURCECFG_BASE 0x0004
49 #define APLIC_SOURCECFG_D (1 << 10)
50 #define APLIC_SOURCECFG_CHILDIDX_MASK 0x000003ff
51 #define APLIC_SOURCECFG_SM_MASK 0x00000007
52 #define APLIC_SOURCECFG_SM_INACTIVE 0x0
53 #define APLIC_SOURCECFG_SM_DETACH 0x1
54 #define APLIC_SOURCECFG_SM_EDGE_RISE 0x4
55 #define APLIC_SOURCECFG_SM_EDGE_FALL 0x5
56 #define APLIC_SOURCECFG_SM_LEVEL_HIGH 0x6
57 #define APLIC_SOURCECFG_SM_LEVEL_LOW 0x7
59 #define APLIC_MMSICFGADDR 0x1bc0
60 #define APLIC_MMSICFGADDRH 0x1bc4
61 #define APLIC_SMSICFGADDR 0x1bc8
62 #define APLIC_SMSICFGADDRH 0x1bcc
64 #define APLIC_xMSICFGADDRH_L (1UL << 31)
65 #define APLIC_xMSICFGADDRH_HHXS_MASK 0x1f
66 #define APLIC_xMSICFGADDRH_HHXS_SHIFT 24
67 #define APLIC_xMSICFGADDRH_LHXS_MASK 0x7
68 #define APLIC_xMSICFGADDRH_LHXS_SHIFT 20
69 #define APLIC_xMSICFGADDRH_HHXW_MASK 0x7
70 #define APLIC_xMSICFGADDRH_HHXW_SHIFT 16
71 #define APLIC_xMSICFGADDRH_LHXW_MASK 0xf
72 #define APLIC_xMSICFGADDRH_LHXW_SHIFT 12
73 #define APLIC_xMSICFGADDRH_BAPPN_MASK 0xfff
75 #define APLIC_xMSICFGADDR_PPN_SHIFT 12
77 #define APLIC_xMSICFGADDR_PPN_HART(__lhxs) \
78 ((1UL << (__lhxs)) - 1)
80 #define APLIC_xMSICFGADDR_PPN_LHX_MASK(__lhxw) \
81 ((1UL << (__lhxw)) - 1)
82 #define APLIC_xMSICFGADDR_PPN_LHX_SHIFT(__lhxs) \
84 #define APLIC_xMSICFGADDR_PPN_LHX(__lhxw, __lhxs) \
85 (APLIC_xMSICFGADDR_PPN_LHX_MASK(__lhxw) << \
86 APLIC_xMSICFGADDR_PPN_LHX_SHIFT(__lhxs))
88 #define APLIC_xMSICFGADDR_PPN_HHX_MASK(__hhxw) \
89 ((1UL << (__hhxw)) - 1)
90 #define APLIC_xMSICFGADDR_PPN_HHX_SHIFT(__hhxs) \
91 ((__hhxs) + APLIC_xMSICFGADDR_PPN_SHIFT)
92 #define APLIC_xMSICFGADDR_PPN_HHX(__hhxw, __hhxs) \
93 (APLIC_xMSICFGADDR_PPN_HHX_MASK(__hhxw) << \
94 APLIC_xMSICFGADDR_PPN_HHX_SHIFT(__hhxs))
96 #define APLIC_xMSICFGADDRH_VALID_MASK \
97 (APLIC_xMSICFGADDRH_L | \
98 (APLIC_xMSICFGADDRH_HHXS_MASK << APLIC_xMSICFGADDRH_HHXS_SHIFT) | \
99 (APLIC_xMSICFGADDRH_LHXS_MASK << APLIC_xMSICFGADDRH_LHXS_SHIFT) | \
100 (APLIC_xMSICFGADDRH_HHXW_MASK << APLIC_xMSICFGADDRH_HHXW_SHIFT) | \
101 (APLIC_xMSICFGADDRH_LHXW_MASK << APLIC_xMSICFGADDRH_LHXW_SHIFT) | \
102 APLIC_xMSICFGADDRH_BAPPN_MASK)
104 #define APLIC_SETIP_BASE 0x1c00
105 #define APLIC_SETIPNUM 0x1cdc
107 #define APLIC_CLRIP_BASE 0x1d00
108 #define APLIC_CLRIPNUM 0x1ddc
110 #define APLIC_SETIE_BASE 0x1e00
111 #define APLIC_SETIENUM 0x1edc
113 #define APLIC_CLRIE_BASE 0x1f00
114 #define APLIC_CLRIENUM 0x1fdc
116 #define APLIC_SETIPNUM_LE 0x2000
117 #define APLIC_SETIPNUM_BE 0x2004
119 #define APLIC_ISTATE_PENDING (1U << 0)
120 #define APLIC_ISTATE_ENABLED (1U << 1)
121 #define APLIC_ISTATE_ENPEND (APLIC_ISTATE_ENABLED | \
122 APLIC_ISTATE_PENDING)
123 #define APLIC_ISTATE_INPUT (1U << 8)
125 #define APLIC_GENMSI 0x3000
127 #define APLIC_TARGET_BASE 0x3004
128 #define APLIC_TARGET_HART_IDX_SHIFT 18
129 #define APLIC_TARGET_HART_IDX_MASK 0x3fff
130 #define APLIC_TARGET_GUEST_IDX_SHIFT 12
131 #define APLIC_TARGET_GUEST_IDX_MASK 0x3f
132 #define APLIC_TARGET_IPRIO_MASK 0xff
133 #define APLIC_TARGET_EIID_MASK 0x7ff
135 #define APLIC_IDC_BASE 0x4000
136 #define APLIC_IDC_SIZE 32
138 #define APLIC_IDC_IDELIVERY 0x00
140 #define APLIC_IDC_IFORCE 0x04
142 #define APLIC_IDC_ITHRESHOLD 0x08
144 #define APLIC_IDC_TOPI 0x18
145 #define APLIC_IDC_TOPI_ID_SHIFT 16
146 #define APLIC_IDC_TOPI_ID_MASK 0x3ff
147 #define APLIC_IDC_TOPI_PRIO_MASK 0xff
149 #define APLIC_IDC_CLAIMI 0x1c
151 static uint32_t riscv_aplic_read_input_word(RISCVAPLICState
*aplic
,
154 uint32_t i
, irq
, ret
= 0;
156 for (i
= 0; i
< 32; i
++) {
158 if (!irq
|| aplic
->num_irqs
<= irq
) {
162 ret
|= ((aplic
->state
[irq
] & APLIC_ISTATE_INPUT
) ? 1 : 0) << i
;
168 static uint32_t riscv_aplic_read_pending_word(RISCVAPLICState
*aplic
,
171 uint32_t i
, irq
, ret
= 0;
173 for (i
= 0; i
< 32; i
++) {
175 if (!irq
|| aplic
->num_irqs
<= irq
) {
179 ret
|= ((aplic
->state
[irq
] & APLIC_ISTATE_PENDING
) ? 1 : 0) << i
;
185 static void riscv_aplic_set_pending_raw(RISCVAPLICState
*aplic
,
186 uint32_t irq
, bool pending
)
189 aplic
->state
[irq
] |= APLIC_ISTATE_PENDING
;
191 aplic
->state
[irq
] &= ~APLIC_ISTATE_PENDING
;
195 static void riscv_aplic_set_pending(RISCVAPLICState
*aplic
,
196 uint32_t irq
, bool pending
)
198 uint32_t sourcecfg
, sm
;
200 if ((irq
<= 0) || (aplic
->num_irqs
<= irq
)) {
204 sourcecfg
= aplic
->sourcecfg
[irq
];
205 if (sourcecfg
& APLIC_SOURCECFG_D
) {
209 sm
= sourcecfg
& APLIC_SOURCECFG_SM_MASK
;
210 if ((sm
== APLIC_SOURCECFG_SM_INACTIVE
) ||
211 ((!aplic
->msimode
|| (aplic
->msimode
&& !pending
)) &&
212 ((sm
== APLIC_SOURCECFG_SM_LEVEL_HIGH
) ||
213 (sm
== APLIC_SOURCECFG_SM_LEVEL_LOW
)))) {
217 riscv_aplic_set_pending_raw(aplic
, irq
, pending
);
220 static void riscv_aplic_set_pending_word(RISCVAPLICState
*aplic
,
221 uint32_t word
, uint32_t value
,
226 for (i
= 0; i
< 32; i
++) {
228 if (!irq
|| aplic
->num_irqs
<= irq
) {
232 if (value
& (1U << i
)) {
233 riscv_aplic_set_pending(aplic
, irq
, pending
);
238 static uint32_t riscv_aplic_read_enabled_word(RISCVAPLICState
*aplic
,
241 uint32_t i
, irq
, ret
= 0;
243 for (i
= 0; i
< 32; i
++) {
245 if (!irq
|| aplic
->num_irqs
<= irq
) {
249 ret
|= ((aplic
->state
[irq
] & APLIC_ISTATE_ENABLED
) ? 1 : 0) << i
;
255 static void riscv_aplic_set_enabled_raw(RISCVAPLICState
*aplic
,
256 uint32_t irq
, bool enabled
)
259 aplic
->state
[irq
] |= APLIC_ISTATE_ENABLED
;
261 aplic
->state
[irq
] &= ~APLIC_ISTATE_ENABLED
;
265 static void riscv_aplic_set_enabled(RISCVAPLICState
*aplic
,
266 uint32_t irq
, bool enabled
)
268 uint32_t sourcecfg
, sm
;
270 if ((irq
<= 0) || (aplic
->num_irqs
<= irq
)) {
274 sourcecfg
= aplic
->sourcecfg
[irq
];
275 if (sourcecfg
& APLIC_SOURCECFG_D
) {
279 sm
= sourcecfg
& APLIC_SOURCECFG_SM_MASK
;
280 if (sm
== APLIC_SOURCECFG_SM_INACTIVE
) {
284 riscv_aplic_set_enabled_raw(aplic
, irq
, enabled
);
287 static void riscv_aplic_set_enabled_word(RISCVAPLICState
*aplic
,
288 uint32_t word
, uint32_t value
,
293 for (i
= 0; i
< 32; i
++) {
295 if (!irq
|| aplic
->num_irqs
<= irq
) {
299 if (value
& (1U << i
)) {
300 riscv_aplic_set_enabled(aplic
, irq
, enabled
);
305 static void riscv_aplic_msi_send(RISCVAPLICState
*aplic
,
306 uint32_t hart_idx
, uint32_t guest_idx
,
311 RISCVAPLICState
*aplic_m
;
312 uint32_t lhxs
, lhxw
, hhxs
, hhxw
, group_idx
, msicfgaddr
, msicfgaddrH
;
315 while (aplic_m
&& !aplic_m
->mmode
) {
316 aplic_m
= aplic_m
->parent
;
319 qemu_log_mask(LOG_GUEST_ERROR
, "%s: m-level APLIC not found\n",
325 msicfgaddr
= aplic_m
->mmsicfgaddr
;
326 msicfgaddrH
= aplic_m
->mmsicfgaddrH
;
328 msicfgaddr
= aplic_m
->smsicfgaddr
;
329 msicfgaddrH
= aplic_m
->smsicfgaddrH
;
332 lhxs
= (msicfgaddrH
>> APLIC_xMSICFGADDRH_LHXS_SHIFT
) &
333 APLIC_xMSICFGADDRH_LHXS_MASK
;
334 lhxw
= (msicfgaddrH
>> APLIC_xMSICFGADDRH_LHXW_SHIFT
) &
335 APLIC_xMSICFGADDRH_LHXW_MASK
;
336 hhxs
= (msicfgaddrH
>> APLIC_xMSICFGADDRH_HHXS_SHIFT
) &
337 APLIC_xMSICFGADDRH_HHXS_MASK
;
338 hhxw
= (msicfgaddrH
>> APLIC_xMSICFGADDRH_HHXW_SHIFT
) &
339 APLIC_xMSICFGADDRH_HHXW_MASK
;
341 group_idx
= hart_idx
>> lhxw
;
342 hart_idx
&= APLIC_xMSICFGADDR_PPN_LHX_MASK(lhxw
);
345 addr
|= ((uint64_t)(msicfgaddrH
& APLIC_xMSICFGADDRH_BAPPN_MASK
)) << 32;
346 addr
|= ((uint64_t)(group_idx
& APLIC_xMSICFGADDR_PPN_HHX_MASK(hhxw
))) <<
347 APLIC_xMSICFGADDR_PPN_HHX_SHIFT(hhxs
);
348 addr
|= ((uint64_t)(hart_idx
& APLIC_xMSICFGADDR_PPN_LHX_MASK(lhxw
))) <<
349 APLIC_xMSICFGADDR_PPN_LHX_SHIFT(lhxs
);
350 addr
|= (uint64_t)(guest_idx
& APLIC_xMSICFGADDR_PPN_HART(lhxs
));
351 addr
<<= APLIC_xMSICFGADDR_PPN_SHIFT
;
353 address_space_stl_le(&address_space_memory
, addr
,
354 eiid
, MEMTXATTRS_UNSPECIFIED
, &result
);
355 if (result
!= MEMTX_OK
) {
356 qemu_log_mask(LOG_GUEST_ERROR
, "%s: MSI write failed for "
357 "hart_index=%d guest_index=%d eiid=%d\n",
358 __func__
, hart_idx
, guest_idx
, eiid
);
362 static void riscv_aplic_msi_irq_update(RISCVAPLICState
*aplic
, uint32_t irq
)
364 uint32_t hart_idx
, guest_idx
, eiid
;
366 if (!aplic
->msimode
|| (aplic
->num_irqs
<= irq
) ||
367 !(aplic
->domaincfg
& APLIC_DOMAINCFG_IE
)) {
371 if ((aplic
->state
[irq
] & APLIC_ISTATE_ENPEND
) != APLIC_ISTATE_ENPEND
) {
375 riscv_aplic_set_pending_raw(aplic
, irq
, false);
377 hart_idx
= aplic
->target
[irq
] >> APLIC_TARGET_HART_IDX_SHIFT
;
378 hart_idx
&= APLIC_TARGET_HART_IDX_MASK
;
380 /* M-level APLIC ignores guest_index */
383 guest_idx
= aplic
->target
[irq
] >> APLIC_TARGET_GUEST_IDX_SHIFT
;
384 guest_idx
&= APLIC_TARGET_GUEST_IDX_MASK
;
386 eiid
= aplic
->target
[irq
] & APLIC_TARGET_EIID_MASK
;
387 riscv_aplic_msi_send(aplic
, hart_idx
, guest_idx
, eiid
);
390 static uint32_t riscv_aplic_idc_topi(RISCVAPLICState
*aplic
, uint32_t idc
)
392 uint32_t best_irq
, best_iprio
;
393 uint32_t irq
, iprio
, ihartidx
, ithres
;
395 if (aplic
->num_harts
<= idc
) {
399 ithres
= aplic
->ithreshold
[idc
];
400 best_irq
= best_iprio
= UINT32_MAX
;
401 for (irq
= 1; irq
< aplic
->num_irqs
; irq
++) {
402 if ((aplic
->state
[irq
] & APLIC_ISTATE_ENPEND
) !=
403 APLIC_ISTATE_ENPEND
) {
407 ihartidx
= aplic
->target
[irq
] >> APLIC_TARGET_HART_IDX_SHIFT
;
408 ihartidx
&= APLIC_TARGET_HART_IDX_MASK
;
409 if (ihartidx
!= idc
) {
413 iprio
= aplic
->target
[irq
] & aplic
->iprio_mask
;
414 if (ithres
&& iprio
>= ithres
) {
418 if (iprio
< best_iprio
) {
424 if (best_irq
< aplic
->num_irqs
&& best_iprio
<= aplic
->iprio_mask
) {
425 return (best_irq
<< APLIC_IDC_TOPI_ID_SHIFT
) | best_iprio
;
431 static void riscv_aplic_idc_update(RISCVAPLICState
*aplic
, uint32_t idc
)
435 if (aplic
->msimode
|| aplic
->num_harts
<= idc
) {
439 topi
= riscv_aplic_idc_topi(aplic
, idc
);
440 if ((aplic
->domaincfg
& APLIC_DOMAINCFG_IE
) &&
441 aplic
->idelivery
[idc
] &&
442 (aplic
->iforce
[idc
] || topi
)) {
443 qemu_irq_raise(aplic
->external_irqs
[idc
]);
445 qemu_irq_lower(aplic
->external_irqs
[idc
]);
449 static uint32_t riscv_aplic_idc_claimi(RISCVAPLICState
*aplic
, uint32_t idc
)
451 uint32_t irq
, state
, sm
, topi
= riscv_aplic_idc_topi(aplic
, idc
);
454 aplic
->iforce
[idc
] = 0;
458 irq
= (topi
>> APLIC_IDC_TOPI_ID_SHIFT
) & APLIC_IDC_TOPI_ID_MASK
;
459 sm
= aplic
->sourcecfg
[irq
] & APLIC_SOURCECFG_SM_MASK
;
460 state
= aplic
->state
[irq
];
461 riscv_aplic_set_pending_raw(aplic
, irq
, false);
462 if ((sm
== APLIC_SOURCECFG_SM_LEVEL_HIGH
) &&
463 (state
& APLIC_ISTATE_INPUT
)) {
464 riscv_aplic_set_pending_raw(aplic
, irq
, true);
465 } else if ((sm
== APLIC_SOURCECFG_SM_LEVEL_LOW
) &&
466 !(state
& APLIC_ISTATE_INPUT
)) {
467 riscv_aplic_set_pending_raw(aplic
, irq
, true);
469 riscv_aplic_idc_update(aplic
, idc
);
474 static void riscv_aplic_request(void *opaque
, int irq
, int level
)
477 RISCVAPLICState
*aplic
= opaque
;
478 uint32_t sourcecfg
, childidx
, state
, idc
;
480 assert((0 < irq
) && (irq
< aplic
->num_irqs
));
482 sourcecfg
= aplic
->sourcecfg
[irq
];
483 if (sourcecfg
& APLIC_SOURCECFG_D
) {
484 childidx
= sourcecfg
& APLIC_SOURCECFG_CHILDIDX_MASK
;
485 if (childidx
< aplic
->num_children
) {
486 riscv_aplic_request(aplic
->children
[childidx
], irq
, level
);
491 state
= aplic
->state
[irq
];
492 switch (sourcecfg
& APLIC_SOURCECFG_SM_MASK
) {
493 case APLIC_SOURCECFG_SM_EDGE_RISE
:
494 if ((level
> 0) && !(state
& APLIC_ISTATE_INPUT
) &&
495 !(state
& APLIC_ISTATE_PENDING
)) {
496 riscv_aplic_set_pending_raw(aplic
, irq
, true);
500 case APLIC_SOURCECFG_SM_EDGE_FALL
:
501 if ((level
<= 0) && (state
& APLIC_ISTATE_INPUT
) &&
502 !(state
& APLIC_ISTATE_PENDING
)) {
503 riscv_aplic_set_pending_raw(aplic
, irq
, true);
507 case APLIC_SOURCECFG_SM_LEVEL_HIGH
:
508 if ((level
> 0) && !(state
& APLIC_ISTATE_PENDING
)) {
509 riscv_aplic_set_pending_raw(aplic
, irq
, true);
513 case APLIC_SOURCECFG_SM_LEVEL_LOW
:
514 if ((level
<= 0) && !(state
& APLIC_ISTATE_PENDING
)) {
515 riscv_aplic_set_pending_raw(aplic
, irq
, true);
524 aplic
->state
[irq
] &= ~APLIC_ISTATE_INPUT
;
526 aplic
->state
[irq
] |= APLIC_ISTATE_INPUT
;
530 if (aplic
->msimode
) {
531 riscv_aplic_msi_irq_update(aplic
, irq
);
533 idc
= aplic
->target
[irq
] >> APLIC_TARGET_HART_IDX_SHIFT
;
534 idc
&= APLIC_TARGET_HART_IDX_MASK
;
535 riscv_aplic_idc_update(aplic
, idc
);
540 static uint64_t riscv_aplic_read(void *opaque
, hwaddr addr
, unsigned size
)
542 uint32_t irq
, word
, idc
;
543 RISCVAPLICState
*aplic
= opaque
;
545 /* Reads must be 4 byte words */
546 if ((addr
& 0x3) != 0) {
550 if (addr
== APLIC_DOMAINCFG
) {
551 return APLIC_DOMAINCFG_RDONLY
| aplic
->domaincfg
|
552 (aplic
->msimode
? APLIC_DOMAINCFG_DM
: 0);
553 } else if ((APLIC_SOURCECFG_BASE
<= addr
) &&
554 (addr
< (APLIC_SOURCECFG_BASE
+ (aplic
->num_irqs
- 1) * 4))) {
555 irq
= ((addr
- APLIC_SOURCECFG_BASE
) >> 2) + 1;
556 return aplic
->sourcecfg
[irq
];
557 } else if (aplic
->mmode
&& aplic
->msimode
&&
558 (addr
== APLIC_MMSICFGADDR
)) {
559 return aplic
->mmsicfgaddr
;
560 } else if (aplic
->mmode
&& aplic
->msimode
&&
561 (addr
== APLIC_MMSICFGADDRH
)) {
562 return aplic
->mmsicfgaddrH
;
563 } else if (aplic
->mmode
&& aplic
->msimode
&&
564 (addr
== APLIC_SMSICFGADDR
)) {
566 * Registers SMSICFGADDR and SMSICFGADDRH are implemented only if:
567 * (a) the interrupt domain is at machine level
568 * (b) the domain's harts implement supervisor mode
569 * (c) the domain has one or more child supervisor-level domains
570 * that support MSI delivery mode (domaincfg.DM is not read-
571 * only zero in at least one of the supervisor-level child
574 return (aplic
->num_children
) ? aplic
->smsicfgaddr
: 0;
575 } else if (aplic
->mmode
&& aplic
->msimode
&&
576 (addr
== APLIC_SMSICFGADDRH
)) {
577 return (aplic
->num_children
) ? aplic
->smsicfgaddrH
: 0;
578 } else if ((APLIC_SETIP_BASE
<= addr
) &&
579 (addr
< (APLIC_SETIP_BASE
+ aplic
->bitfield_words
* 4))) {
580 word
= (addr
- APLIC_SETIP_BASE
) >> 2;
581 return riscv_aplic_read_pending_word(aplic
, word
);
582 } else if (addr
== APLIC_SETIPNUM
) {
584 } else if ((APLIC_CLRIP_BASE
<= addr
) &&
585 (addr
< (APLIC_CLRIP_BASE
+ aplic
->bitfield_words
* 4))) {
586 word
= (addr
- APLIC_CLRIP_BASE
) >> 2;
587 return riscv_aplic_read_input_word(aplic
, word
);
588 } else if (addr
== APLIC_CLRIPNUM
) {
590 } else if ((APLIC_SETIE_BASE
<= addr
) &&
591 (addr
< (APLIC_SETIE_BASE
+ aplic
->bitfield_words
* 4))) {
592 word
= (addr
- APLIC_SETIE_BASE
) >> 2;
593 return riscv_aplic_read_enabled_word(aplic
, word
);
594 } else if (addr
== APLIC_SETIENUM
) {
596 } else if ((APLIC_CLRIE_BASE
<= addr
) &&
597 (addr
< (APLIC_CLRIE_BASE
+ aplic
->bitfield_words
* 4))) {
599 } else if (addr
== APLIC_CLRIENUM
) {
601 } else if (addr
== APLIC_SETIPNUM_LE
) {
603 } else if (addr
== APLIC_SETIPNUM_BE
) {
605 } else if (addr
== APLIC_GENMSI
) {
606 return (aplic
->msimode
) ? aplic
->genmsi
: 0;
607 } else if ((APLIC_TARGET_BASE
<= addr
) &&
608 (addr
< (APLIC_TARGET_BASE
+ (aplic
->num_irqs
- 1) * 4))) {
609 irq
= ((addr
- APLIC_TARGET_BASE
) >> 2) + 1;
610 return aplic
->target
[irq
];
611 } else if (!aplic
->msimode
&& (APLIC_IDC_BASE
<= addr
) &&
612 (addr
< (APLIC_IDC_BASE
+ aplic
->num_harts
* APLIC_IDC_SIZE
))) {
613 idc
= (addr
- APLIC_IDC_BASE
) / APLIC_IDC_SIZE
;
614 switch (addr
- (APLIC_IDC_BASE
+ idc
* APLIC_IDC_SIZE
)) {
615 case APLIC_IDC_IDELIVERY
:
616 return aplic
->idelivery
[idc
];
617 case APLIC_IDC_IFORCE
:
618 return aplic
->iforce
[idc
];
619 case APLIC_IDC_ITHRESHOLD
:
620 return aplic
->ithreshold
[idc
];
622 return riscv_aplic_idc_topi(aplic
, idc
);
623 case APLIC_IDC_CLAIMI
:
624 return riscv_aplic_idc_claimi(aplic
, idc
);
631 qemu_log_mask(LOG_GUEST_ERROR
,
632 "%s: Invalid register read 0x%" HWADDR_PRIx
"\n",
637 static void riscv_aplic_write(void *opaque
, hwaddr addr
, uint64_t value
,
640 RISCVAPLICState
*aplic
= opaque
;
641 uint32_t irq
, word
, idc
= UINT32_MAX
;
643 /* Writes must be 4 byte words */
644 if ((addr
& 0x3) != 0) {
648 if (addr
== APLIC_DOMAINCFG
) {
649 /* Only IE bit writable at the moment */
650 value
&= APLIC_DOMAINCFG_IE
;
651 aplic
->domaincfg
= value
;
652 } else if ((APLIC_SOURCECFG_BASE
<= addr
) &&
653 (addr
< (APLIC_SOURCECFG_BASE
+ (aplic
->num_irqs
- 1) * 4))) {
654 irq
= ((addr
- APLIC_SOURCECFG_BASE
) >> 2) + 1;
655 if (!aplic
->num_children
&& (value
& APLIC_SOURCECFG_D
)) {
658 if (value
& APLIC_SOURCECFG_D
) {
659 value
&= (APLIC_SOURCECFG_D
| APLIC_SOURCECFG_CHILDIDX_MASK
);
661 value
&= (APLIC_SOURCECFG_D
| APLIC_SOURCECFG_SM_MASK
);
663 aplic
->sourcecfg
[irq
] = value
;
664 if ((aplic
->sourcecfg
[irq
] & APLIC_SOURCECFG_D
) ||
665 (aplic
->sourcecfg
[irq
] == 0)) {
666 riscv_aplic_set_pending_raw(aplic
, irq
, false);
667 riscv_aplic_set_enabled_raw(aplic
, irq
, false);
669 } else if (aplic
->mmode
&& aplic
->msimode
&&
670 (addr
== APLIC_MMSICFGADDR
)) {
671 if (!(aplic
->mmsicfgaddrH
& APLIC_xMSICFGADDRH_L
)) {
672 aplic
->mmsicfgaddr
= value
;
674 } else if (aplic
->mmode
&& aplic
->msimode
&&
675 (addr
== APLIC_MMSICFGADDRH
)) {
676 if (!(aplic
->mmsicfgaddrH
& APLIC_xMSICFGADDRH_L
)) {
677 aplic
->mmsicfgaddrH
= value
& APLIC_xMSICFGADDRH_VALID_MASK
;
679 } else if (aplic
->mmode
&& aplic
->msimode
&&
680 (addr
== APLIC_SMSICFGADDR
)) {
682 * Registers SMSICFGADDR and SMSICFGADDRH are implemented only if:
683 * (a) the interrupt domain is at machine level
684 * (b) the domain's harts implement supervisor mode
685 * (c) the domain has one or more child supervisor-level domains
686 * that support MSI delivery mode (domaincfg.DM is not read-
687 * only zero in at least one of the supervisor-level child
690 if (aplic
->num_children
&&
691 !(aplic
->smsicfgaddrH
& APLIC_xMSICFGADDRH_L
)) {
692 aplic
->smsicfgaddr
= value
;
694 } else if (aplic
->mmode
&& aplic
->msimode
&&
695 (addr
== APLIC_SMSICFGADDRH
)) {
696 if (aplic
->num_children
&&
697 !(aplic
->smsicfgaddrH
& APLIC_xMSICFGADDRH_L
)) {
698 aplic
->smsicfgaddrH
= value
& APLIC_xMSICFGADDRH_VALID_MASK
;
700 } else if ((APLIC_SETIP_BASE
<= addr
) &&
701 (addr
< (APLIC_SETIP_BASE
+ aplic
->bitfield_words
* 4))) {
702 word
= (addr
- APLIC_SETIP_BASE
) >> 2;
703 riscv_aplic_set_pending_word(aplic
, word
, value
, true);
704 } else if (addr
== APLIC_SETIPNUM
) {
705 riscv_aplic_set_pending(aplic
, value
, true);
706 } else if ((APLIC_CLRIP_BASE
<= addr
) &&
707 (addr
< (APLIC_CLRIP_BASE
+ aplic
->bitfield_words
* 4))) {
708 word
= (addr
- APLIC_CLRIP_BASE
) >> 2;
709 riscv_aplic_set_pending_word(aplic
, word
, value
, false);
710 } else if (addr
== APLIC_CLRIPNUM
) {
711 riscv_aplic_set_pending(aplic
, value
, false);
712 } else if ((APLIC_SETIE_BASE
<= addr
) &&
713 (addr
< (APLIC_SETIE_BASE
+ aplic
->bitfield_words
* 4))) {
714 word
= (addr
- APLIC_SETIE_BASE
) >> 2;
715 riscv_aplic_set_enabled_word(aplic
, word
, value
, true);
716 } else if (addr
== APLIC_SETIENUM
) {
717 riscv_aplic_set_enabled(aplic
, value
, true);
718 } else if ((APLIC_CLRIE_BASE
<= addr
) &&
719 (addr
< (APLIC_CLRIE_BASE
+ aplic
->bitfield_words
* 4))) {
720 word
= (addr
- APLIC_CLRIE_BASE
) >> 2;
721 riscv_aplic_set_enabled_word(aplic
, word
, value
, false);
722 } else if (addr
== APLIC_CLRIENUM
) {
723 riscv_aplic_set_enabled(aplic
, value
, false);
724 } else if (addr
== APLIC_SETIPNUM_LE
) {
725 riscv_aplic_set_pending(aplic
, value
, true);
726 } else if (addr
== APLIC_SETIPNUM_BE
) {
727 riscv_aplic_set_pending(aplic
, bswap32(value
), true);
728 } else if (addr
== APLIC_GENMSI
) {
729 if (aplic
->msimode
) {
730 aplic
->genmsi
= value
& ~(APLIC_TARGET_GUEST_IDX_MASK
<<
731 APLIC_TARGET_GUEST_IDX_SHIFT
);
732 riscv_aplic_msi_send(aplic
,
733 value
>> APLIC_TARGET_HART_IDX_SHIFT
,
735 value
& APLIC_TARGET_EIID_MASK
);
737 } else if ((APLIC_TARGET_BASE
<= addr
) &&
738 (addr
< (APLIC_TARGET_BASE
+ (aplic
->num_irqs
- 1) * 4))) {
739 irq
= ((addr
- APLIC_TARGET_BASE
) >> 2) + 1;
740 if (aplic
->msimode
) {
741 aplic
->target
[irq
] = value
;
743 aplic
->target
[irq
] = (value
& ~APLIC_TARGET_IPRIO_MASK
) |
744 ((value
& aplic
->iprio_mask
) ?
745 (value
& aplic
->iprio_mask
) : 1);
747 } else if (!aplic
->msimode
&& (APLIC_IDC_BASE
<= addr
) &&
748 (addr
< (APLIC_IDC_BASE
+ aplic
->num_harts
* APLIC_IDC_SIZE
))) {
749 idc
= (addr
- APLIC_IDC_BASE
) / APLIC_IDC_SIZE
;
750 switch (addr
- (APLIC_IDC_BASE
+ idc
* APLIC_IDC_SIZE
)) {
751 case APLIC_IDC_IDELIVERY
:
752 aplic
->idelivery
[idc
] = value
& 0x1;
754 case APLIC_IDC_IFORCE
:
755 aplic
->iforce
[idc
] = value
& 0x1;
757 case APLIC_IDC_ITHRESHOLD
:
758 aplic
->ithreshold
[idc
] = value
& aplic
->iprio_mask
;
767 if (aplic
->msimode
) {
768 for (irq
= 1; irq
< aplic
->num_irqs
; irq
++) {
769 riscv_aplic_msi_irq_update(aplic
, irq
);
772 if (idc
== UINT32_MAX
) {
773 for (idc
= 0; idc
< aplic
->num_harts
; idc
++) {
774 riscv_aplic_idc_update(aplic
, idc
);
777 riscv_aplic_idc_update(aplic
, idc
);
784 qemu_log_mask(LOG_GUEST_ERROR
,
785 "%s: Invalid register write 0x%" HWADDR_PRIx
"\n",
789 static const MemoryRegionOps riscv_aplic_ops
= {
790 .read
= riscv_aplic_read
,
791 .write
= riscv_aplic_write
,
792 .endianness
= DEVICE_LITTLE_ENDIAN
,
794 .min_access_size
= 4,
799 static void riscv_aplic_realize(DeviceState
*dev
, Error
**errp
)
802 RISCVAPLICState
*aplic
= RISCV_APLIC(dev
);
804 aplic
->bitfield_words
= (aplic
->num_irqs
+ 31) >> 5;
805 aplic
->sourcecfg
= g_new0(uint32_t, aplic
->num_irqs
);
806 aplic
->state
= g_new(uint32_t, aplic
->num_irqs
);
807 aplic
->target
= g_new0(uint32_t, aplic
->num_irqs
);
808 if (!aplic
->msimode
) {
809 for (i
= 0; i
< aplic
->num_irqs
; i
++) {
810 aplic
->target
[i
] = 1;
813 aplic
->idelivery
= g_new0(uint32_t, aplic
->num_harts
);
814 aplic
->iforce
= g_new0(uint32_t, aplic
->num_harts
);
815 aplic
->ithreshold
= g_new0(uint32_t, aplic
->num_harts
);
817 memory_region_init_io(&aplic
->mmio
, OBJECT(dev
), &riscv_aplic_ops
, aplic
,
818 TYPE_RISCV_APLIC
, aplic
->aperture_size
);
819 sysbus_init_mmio(SYS_BUS_DEVICE(dev
), &aplic
->mmio
);
822 * Only root APLICs have hardware IRQ lines. All non-root APLICs
823 * have IRQ lines delegated by their parent APLIC.
825 if (!aplic
->parent
) {
826 qdev_init_gpio_in(dev
, riscv_aplic_request
, aplic
->num_irqs
);
829 /* Create output IRQ lines for non-MSI mode */
830 if (!aplic
->msimode
) {
831 aplic
->external_irqs
= g_malloc(sizeof(qemu_irq
) * aplic
->num_harts
);
832 qdev_init_gpio_out(dev
, aplic
->external_irqs
, aplic
->num_harts
);
834 /* Claim the CPU interrupt to be triggered by this APLIC */
835 for (i
= 0; i
< aplic
->num_harts
; i
++) {
836 RISCVCPU
*cpu
= RISCV_CPU(qemu_get_cpu(aplic
->hartid_base
+ i
));
837 if (riscv_cpu_claim_interrupts(cpu
,
838 (aplic
->mmode
) ? MIP_MEIP
: MIP_SEIP
) < 0) {
839 error_report("%s already claimed",
840 (aplic
->mmode
) ? "MEIP" : "SEIP");
846 msi_nonbroken
= true;
849 static Property riscv_aplic_properties
[] = {
850 DEFINE_PROP_UINT32("aperture-size", RISCVAPLICState
, aperture_size
, 0),
851 DEFINE_PROP_UINT32("hartid-base", RISCVAPLICState
, hartid_base
, 0),
852 DEFINE_PROP_UINT32("num-harts", RISCVAPLICState
, num_harts
, 0),
853 DEFINE_PROP_UINT32("iprio-mask", RISCVAPLICState
, iprio_mask
, 0),
854 DEFINE_PROP_UINT32("num-irqs", RISCVAPLICState
, num_irqs
, 0),
855 DEFINE_PROP_BOOL("msimode", RISCVAPLICState
, msimode
, 0),
856 DEFINE_PROP_BOOL("mmode", RISCVAPLICState
, mmode
, 0),
857 DEFINE_PROP_END_OF_LIST(),
860 static const VMStateDescription vmstate_riscv_aplic
= {
861 .name
= "riscv_aplic",
863 .minimum_version_id
= 1,
864 .fields
= (VMStateField
[]) {
865 VMSTATE_UINT32(domaincfg
, RISCVAPLICState
),
866 VMSTATE_UINT32(mmsicfgaddr
, RISCVAPLICState
),
867 VMSTATE_UINT32(mmsicfgaddrH
, RISCVAPLICState
),
868 VMSTATE_UINT32(smsicfgaddr
, RISCVAPLICState
),
869 VMSTATE_UINT32(smsicfgaddrH
, RISCVAPLICState
),
870 VMSTATE_UINT32(genmsi
, RISCVAPLICState
),
871 VMSTATE_VARRAY_UINT32(sourcecfg
, RISCVAPLICState
,
873 vmstate_info_uint32
, uint32_t),
874 VMSTATE_VARRAY_UINT32(state
, RISCVAPLICState
,
876 vmstate_info_uint32
, uint32_t),
877 VMSTATE_VARRAY_UINT32(target
, RISCVAPLICState
,
879 vmstate_info_uint32
, uint32_t),
880 VMSTATE_VARRAY_UINT32(idelivery
, RISCVAPLICState
,
882 vmstate_info_uint32
, uint32_t),
883 VMSTATE_VARRAY_UINT32(iforce
, RISCVAPLICState
,
885 vmstate_info_uint32
, uint32_t),
886 VMSTATE_VARRAY_UINT32(ithreshold
, RISCVAPLICState
,
888 vmstate_info_uint32
, uint32_t),
889 VMSTATE_END_OF_LIST()
893 static void riscv_aplic_class_init(ObjectClass
*klass
, void *data
)
895 DeviceClass
*dc
= DEVICE_CLASS(klass
);
897 device_class_set_props(dc
, riscv_aplic_properties
);
898 dc
->realize
= riscv_aplic_realize
;
899 dc
->vmsd
= &vmstate_riscv_aplic
;
902 static const TypeInfo riscv_aplic_info
= {
903 .name
= TYPE_RISCV_APLIC
,
904 .parent
= TYPE_SYS_BUS_DEVICE
,
905 .instance_size
= sizeof(RISCVAPLICState
),
906 .class_init
= riscv_aplic_class_init
,
909 static void riscv_aplic_register_types(void)
911 type_register_static(&riscv_aplic_info
);
914 type_init(riscv_aplic_register_types
)
917 * Add a APLIC device to another APLIC device as child for
918 * interrupt delegation.
920 void riscv_aplic_add_child(DeviceState
*parent
, DeviceState
*child
)
922 RISCVAPLICState
*caplic
, *paplic
;
924 assert(parent
&& child
);
925 caplic
= RISCV_APLIC(child
);
926 paplic
= RISCV_APLIC(parent
);
928 assert(paplic
->num_irqs
== caplic
->num_irqs
);
929 assert(paplic
->num_children
<= QEMU_APLIC_MAX_CHILDREN
);
931 caplic
->parent
= paplic
;
932 paplic
->children
[paplic
->num_children
] = caplic
;
933 paplic
->num_children
++;
937 * Create APLIC device.
939 DeviceState
*riscv_aplic_create(hwaddr addr
, hwaddr size
,
940 uint32_t hartid_base
, uint32_t num_harts
, uint32_t num_sources
,
941 uint32_t iprio_bits
, bool msimode
, bool mmode
, DeviceState
*parent
)
943 DeviceState
*dev
= qdev_new(TYPE_RISCV_APLIC
);
946 assert(num_harts
< APLIC_MAX_IDC
);
947 assert((APLIC_IDC_BASE
+ (num_harts
* APLIC_IDC_SIZE
)) <= size
);
948 assert(num_sources
< APLIC_MAX_SOURCE
);
949 assert(APLIC_MIN_IPRIO_BITS
<= iprio_bits
);
950 assert(iprio_bits
<= APLIC_MAX_IPRIO_BITS
);
952 qdev_prop_set_uint32(dev
, "aperture-size", size
);
953 qdev_prop_set_uint32(dev
, "hartid-base", hartid_base
);
954 qdev_prop_set_uint32(dev
, "num-harts", num_harts
);
955 qdev_prop_set_uint32(dev
, "iprio-mask", ((1U << iprio_bits
) - 1));
956 qdev_prop_set_uint32(dev
, "num-irqs", num_sources
+ 1);
957 qdev_prop_set_bit(dev
, "msimode", msimode
);
958 qdev_prop_set_bit(dev
, "mmode", mmode
);
960 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev
), &error_fatal
);
961 sysbus_mmio_map(SYS_BUS_DEVICE(dev
), 0, addr
);
964 riscv_aplic_add_child(parent
, dev
);
968 for (i
= 0; i
< num_harts
; i
++) {
969 CPUState
*cpu
= qemu_get_cpu(hartid_base
+ i
);
971 qdev_connect_gpio_out_named(dev
, NULL
, i
,
972 qdev_get_gpio_in(DEVICE(cpu
),
973 (mmode
) ? IRQ_M_EXT
: IRQ_S_EXT
));