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