xref: /qemu/hw/intc/riscv_aclint.c (revision e240f6cc25917f3138d9e95e0343ae23b63a3f8c)
1 /*
2  * RISC-V ACLINT (Advanced Core Local Interruptor)
3  * URL: https://github.com/riscv/riscv-aclint
4  *
5  * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
6  * Copyright (c) 2017 SiFive, Inc.
7  * Copyright (c) 2021 Western Digital Corporation or its affiliates.
8  *
9  * This provides real-time clock, timer and interprocessor interrupts.
10  *
11  * This program is free software; you can redistribute it and/or modify it
12  * under the terms and conditions of the GNU General Public License,
13  * version 2 or later, as published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18  * more details.
19  *
20  * You should have received a copy of the GNU General Public License along with
21  * this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 #include "qemu/osdep.h"
25 #include "qapi/error.h"
26 #include "qemu/error-report.h"
27 #include "qemu/log.h"
28 #include "qemu/module.h"
29 #include "hw/sysbus.h"
30 #include "target/riscv/cpu.h"
31 #include "target/riscv/time_helper.h"
32 #include "hw/qdev-properties.h"
33 #include "hw/intc/riscv_aclint.h"
34 #include "qemu/timer.h"
35 #include "hw/irq.h"
36 #include "migration/vmstate.h"
37 
38 typedef struct riscv_aclint_mtimer_callback {
39     RISCVAclintMTimerState *s;
40     int num;
41 } riscv_aclint_mtimer_callback;
42 
cpu_riscv_read_rtc_raw(uint32_t timebase_freq)43 static uint64_t cpu_riscv_read_rtc_raw(uint32_t timebase_freq)
44 {
45     return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
46         timebase_freq, NANOSECONDS_PER_SECOND);
47 }
48 
cpu_riscv_read_rtc(void * opaque)49 static uint64_t cpu_riscv_read_rtc(void *opaque)
50 {
51     RISCVAclintMTimerState *mtimer = opaque;
52     return cpu_riscv_read_rtc_raw(mtimer->timebase_freq) + mtimer->time_delta;
53 }
54 
55 /*
56  * Called when timecmp is written to update the QEMU timer or immediately
57  * trigger timer interrupt if mtimecmp <= current timer value.
58  */
riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState * mtimer,RISCVCPU * cpu,int hartid,uint64_t value)59 static void riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState *mtimer,
60                                               RISCVCPU *cpu,
61                                               int hartid,
62                                               uint64_t value)
63 {
64     uint32_t timebase_freq = mtimer->timebase_freq;
65     uint64_t next;
66     uint64_t diff;
67 
68     uint64_t rtc = cpu_riscv_read_rtc(mtimer);
69 
70     /* Compute the relative hartid w.r.t the socket */
71     hartid = hartid - mtimer->hartid_base;
72 
73     mtimer->timecmp[hartid] = value;
74     if (mtimer->timecmp[hartid] <= rtc) {
75         /*
76          * If we're setting an MTIMECMP value in the "past",
77          * immediately raise the timer interrupt
78          */
79         qemu_irq_raise(mtimer->timer_irqs[hartid]);
80         return;
81     }
82 
83     /* otherwise, set up the future timer interrupt */
84     qemu_irq_lower(mtimer->timer_irqs[hartid]);
85     diff = mtimer->timecmp[hartid] - rtc;
86     /* back to ns (note args switched in muldiv64) */
87     uint64_t ns_diff = muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
88 
89     /*
90      * check if ns_diff overflowed and check if the addition would potentially
91      * overflow
92      */
93     if ((NANOSECONDS_PER_SECOND > timebase_freq && ns_diff < diff) ||
94         ns_diff > INT64_MAX) {
95         next = INT64_MAX;
96     } else {
97         /*
98          * as it is very unlikely qemu_clock_get_ns will return a value
99          * greater than INT64_MAX, no additional check is needed for an
100          * unsigned integer overflow.
101          */
102         next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns_diff;
103         /*
104          * if ns_diff is INT64_MAX next may still be outside the range
105          * of a signed integer.
106          */
107         next = MIN(next, INT64_MAX);
108     }
109 
110     timer_mod(mtimer->timers[hartid], next);
111 }
112 
113 /*
114  * Callback used when the timer set using timer_mod expires.
115  * Should raise the timer interrupt line
116  */
riscv_aclint_mtimer_cb(void * opaque)117 static void riscv_aclint_mtimer_cb(void *opaque)
118 {
119     riscv_aclint_mtimer_callback *state = opaque;
120 
121     qemu_irq_raise(state->s->timer_irqs[state->num]);
122 }
123 
124 /* CPU read MTIMER register */
riscv_aclint_mtimer_read(void * opaque,hwaddr addr,unsigned size)125 static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr,
126     unsigned size)
127 {
128     RISCVAclintMTimerState *mtimer = opaque;
129 
130     if (addr >= mtimer->timecmp_base &&
131         addr < (mtimer->timecmp_base + (mtimer->num_harts << 3))) {
132         size_t hartid = mtimer->hartid_base +
133                         ((addr - mtimer->timecmp_base) >> 3);
134         CPUState *cpu = cpu_by_arch_id(hartid);
135         CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;
136         if (!env) {
137             qemu_log_mask(LOG_GUEST_ERROR,
138                           "aclint-mtimer: invalid hartid: %zu", hartid);
139         } else if ((addr & 0x7) == 0) {
140             /* timecmp_lo for RV32/RV64 or timecmp for RV64 */
141             uint64_t timecmp = mtimer->timecmp[hartid];
142             return (size == 4) ? (timecmp & 0xFFFFFFFF) : timecmp;
143         } else if ((addr & 0x7) == 4) {
144             /* timecmp_hi */
145             uint64_t timecmp = mtimer->timecmp[hartid];
146             return (timecmp >> 32) & 0xFFFFFFFF;
147         } else {
148             qemu_log_mask(LOG_UNIMP,
149                           "aclint-mtimer: invalid read: %08x", (uint32_t)addr);
150             return 0;
151         }
152     } else if (addr == mtimer->time_base) {
153         /* time_lo for RV32/RV64 or timecmp for RV64 */
154         uint64_t rtc = cpu_riscv_read_rtc(mtimer);
155         return (size == 4) ? (rtc & 0xFFFFFFFF) : rtc;
156     } else if (addr == mtimer->time_base + 4) {
157         /* time_hi */
158         return (cpu_riscv_read_rtc(mtimer) >> 32) & 0xFFFFFFFF;
159     }
160 
161     qemu_log_mask(LOG_UNIMP,
162                   "aclint-mtimer: invalid read: %08x", (uint32_t)addr);
163     return 0;
164 }
165 
166 /* CPU write MTIMER register */
riscv_aclint_mtimer_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)167 static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
168     uint64_t value, unsigned size)
169 {
170     RISCVAclintMTimerState *mtimer = opaque;
171     int i;
172 
173     if (addr >= mtimer->timecmp_base &&
174         addr < (mtimer->timecmp_base + (mtimer->num_harts << 3))) {
175         size_t hartid = mtimer->hartid_base +
176                         ((addr - mtimer->timecmp_base) >> 3);
177         CPUState *cpu = cpu_by_arch_id(hartid);
178         CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;
179         if (!env) {
180             qemu_log_mask(LOG_GUEST_ERROR,
181                           "aclint-mtimer: invalid hartid: %zu", hartid);
182         } else if ((addr & 0x7) == 0) {
183             if (size == 4) {
184                 /* timecmp_lo for RV32/RV64 */
185                 uint64_t timecmp_hi = mtimer->timecmp[hartid] >> 32;
186                 riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid,
187                     timecmp_hi << 32 | (value & 0xFFFFFFFF));
188             } else {
189                 /* timecmp for RV64 */
190                 riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid,
191                                                   value);
192             }
193         } else if ((addr & 0x7) == 4) {
194             if (size == 4) {
195                 /* timecmp_hi for RV32/RV64 */
196                 uint64_t timecmp_lo = mtimer->timecmp[hartid];
197                 riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid,
198                     value << 32 | (timecmp_lo & 0xFFFFFFFF));
199             } else {
200                 qemu_log_mask(LOG_GUEST_ERROR,
201                               "aclint-mtimer: invalid timecmp_hi write: %08x",
202                               (uint32_t)addr);
203             }
204         } else {
205             qemu_log_mask(LOG_UNIMP,
206                           "aclint-mtimer: invalid timecmp write: %08x",
207                           (uint32_t)addr);
208         }
209         return;
210     } else if (addr == mtimer->time_base || addr == mtimer->time_base + 4) {
211         uint64_t rtc_r = cpu_riscv_read_rtc_raw(mtimer->timebase_freq);
212         uint64_t rtc = cpu_riscv_read_rtc(mtimer);
213 
214         if (addr == mtimer->time_base) {
215             if (size == 4) {
216                 /* time_lo for RV32/RV64 */
217                 mtimer->time_delta = ((rtc & ~0xFFFFFFFFULL) | value) - rtc_r;
218             } else {
219                 /* time for RV64 */
220                 mtimer->time_delta = value - rtc_r;
221             }
222         } else {
223             if (size == 4) {
224                 /* time_hi for RV32/RV64 */
225                 mtimer->time_delta = (value << 32 | (rtc & 0xFFFFFFFF)) - rtc_r;
226             } else {
227                 qemu_log_mask(LOG_GUEST_ERROR,
228                               "aclint-mtimer: invalid time_hi write: %08x",
229                               (uint32_t)addr);
230                 return;
231             }
232         }
233 
234         /* Check if timer interrupt is triggered for each hart. */
235         for (i = 0; i < mtimer->num_harts; i++) {
236             CPUState *cpu = cpu_by_arch_id(mtimer->hartid_base + i);
237             CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;
238             if (!env) {
239                 continue;
240             }
241             riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu),
242                                               mtimer->hartid_base + i,
243                                               mtimer->timecmp[i]);
244             riscv_timer_write_timecmp(env, env->stimer, env->stimecmp, 0, MIP_STIP);
245             riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp,
246                                       env->htimedelta, MIP_VSTIP);
247 
248         }
249         return;
250     }
251 
252     qemu_log_mask(LOG_UNIMP,
253                   "aclint-mtimer: invalid write: %08x", (uint32_t)addr);
254 }
255 
256 static const MemoryRegionOps riscv_aclint_mtimer_ops = {
257     .read = riscv_aclint_mtimer_read,
258     .write = riscv_aclint_mtimer_write,
259     .endianness = DEVICE_LITTLE_ENDIAN,
260     .valid = {
261         .min_access_size = 4,
262         .max_access_size = 8
263     },
264     .impl = {
265         .min_access_size = 4,
266         .max_access_size = 8,
267     }
268 };
269 
270 static const Property riscv_aclint_mtimer_properties[] = {
271     DEFINE_PROP_UINT32("hartid-base", RISCVAclintMTimerState,
272         hartid_base, 0),
273     DEFINE_PROP_UINT32("num-harts", RISCVAclintMTimerState, num_harts, 1),
274     DEFINE_PROP_UINT32("timecmp-base", RISCVAclintMTimerState,
275         timecmp_base, RISCV_ACLINT_DEFAULT_MTIMECMP),
276     DEFINE_PROP_UINT32("time-base", RISCVAclintMTimerState,
277         time_base, RISCV_ACLINT_DEFAULT_MTIME),
278     DEFINE_PROP_UINT32("aperture-size", RISCVAclintMTimerState,
279         aperture_size, RISCV_ACLINT_DEFAULT_MTIMER_SIZE),
280     DEFINE_PROP_UINT32("timebase-freq", RISCVAclintMTimerState,
281         timebase_freq, 0),
282 };
283 
riscv_aclint_mtimer_realize(DeviceState * dev,Error ** errp)284 static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
285 {
286     RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev);
287     int i;
288 
289     memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_mtimer_ops,
290                           s, TYPE_RISCV_ACLINT_MTIMER, s->aperture_size);
291     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
292 
293     s->timer_irqs = g_new(qemu_irq, s->num_harts);
294     qdev_init_gpio_out(dev, s->timer_irqs, s->num_harts);
295 
296     s->timers = g_new0(QEMUTimer *, s->num_harts);
297     s->timecmp = g_new0(uint64_t, s->num_harts);
298     /* Claim timer interrupt bits */
299     for (i = 0; i < s->num_harts; i++) {
300         RISCVCPU *cpu = RISCV_CPU(cpu_by_arch_id(s->hartid_base + i));
301         if (riscv_cpu_claim_interrupts(cpu, MIP_MTIP) < 0) {
302             error_report("MTIP already claimed");
303             exit(1);
304         }
305     }
306 }
307 
riscv_aclint_mtimer_reset_enter(Object * obj,ResetType type)308 static void riscv_aclint_mtimer_reset_enter(Object *obj, ResetType type)
309 {
310     /*
311      * According to RISC-V ACLINT spec:
312      *   - On MTIMER device reset, the MTIME register is cleared to zero.
313      *   - On MTIMER device reset, the MTIMECMP registers are in unknown state.
314      */
315     RISCVAclintMTimerState *mtimer = RISCV_ACLINT_MTIMER(obj);
316 
317     /*
318      * Clear mtime register by writing to 0 it.
319      * Pending mtime interrupts will also be cleared at the same time.
320      */
321     riscv_aclint_mtimer_write(mtimer, mtimer->time_base, 0, 8);
322 }
323 
324 static const VMStateDescription vmstate_riscv_mtimer = {
325     .name = "riscv_mtimer",
326     .version_id = 1,
327     .minimum_version_id = 1,
328     .fields = (const VMStateField[]) {
329             VMSTATE_VARRAY_UINT32(timecmp, RISCVAclintMTimerState,
330                                   num_harts, 0,
331                                   vmstate_info_uint64, uint64_t),
332             VMSTATE_END_OF_LIST()
333         }
334 };
335 
riscv_aclint_mtimer_class_init(ObjectClass * klass,const void * data)336 static void riscv_aclint_mtimer_class_init(ObjectClass *klass, const void *data)
337 {
338     DeviceClass *dc = DEVICE_CLASS(klass);
339     dc->realize = riscv_aclint_mtimer_realize;
340     device_class_set_props(dc, riscv_aclint_mtimer_properties);
341     ResettableClass *rc = RESETTABLE_CLASS(klass);
342     rc->phases.enter = riscv_aclint_mtimer_reset_enter;
343     dc->vmsd = &vmstate_riscv_mtimer;
344 }
345 
346 static const TypeInfo riscv_aclint_mtimer_info = {
347     .name          = TYPE_RISCV_ACLINT_MTIMER,
348     .parent        = TYPE_SYS_BUS_DEVICE,
349     .instance_size = sizeof(RISCVAclintMTimerState),
350     .class_init    = riscv_aclint_mtimer_class_init,
351 };
352 
353 /*
354  * Create ACLINT MTIMER device.
355  */
riscv_aclint_mtimer_create(hwaddr addr,hwaddr size,uint32_t hartid_base,uint32_t num_harts,uint32_t timecmp_base,uint32_t time_base,uint32_t timebase_freq,bool provide_rdtime)356 DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
357     uint32_t hartid_base, uint32_t num_harts,
358     uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
359     bool provide_rdtime)
360 {
361     int i;
362     DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_MTIMER);
363     RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev);
364 
365     assert(num_harts <= RISCV_ACLINT_MAX_HARTS);
366     assert(!(addr & 0x7));
367     assert(!(timecmp_base & 0x7));
368     assert(!(time_base & 0x7));
369 
370     qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
371     qdev_prop_set_uint32(dev, "num-harts", num_harts);
372     qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base);
373     qdev_prop_set_uint32(dev, "time-base", time_base);
374     qdev_prop_set_uint32(dev, "aperture-size", size);
375     qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
376     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
377     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
378 
379     for (i = 0; i < num_harts; i++) {
380         CPUState *cpu = cpu_by_arch_id(hartid_base + i);
381         RISCVCPU *rvcpu = RISCV_CPU(cpu);
382         CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;
383         riscv_aclint_mtimer_callback *cb =
384             g_new0(riscv_aclint_mtimer_callback, 1);
385 
386         if (!env) {
387             g_free(cb);
388             continue;
389         }
390         if (provide_rdtime) {
391             riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, dev);
392         }
393 
394         cb->s = s;
395         cb->num = i;
396         s->timers[i] = timer_new_ns(QEMU_CLOCK_VIRTUAL,
397                                   &riscv_aclint_mtimer_cb, cb);
398         s->timecmp[i] = 0;
399 
400         qdev_connect_gpio_out(dev, i,
401                               qdev_get_gpio_in(DEVICE(rvcpu), IRQ_M_TIMER));
402     }
403 
404     return dev;
405 }
406 
407 /* CPU read [M|S]SWI register */
riscv_aclint_swi_read(void * opaque,hwaddr addr,unsigned size)408 static uint64_t riscv_aclint_swi_read(void *opaque, hwaddr addr,
409     unsigned size)
410 {
411     RISCVAclintSwiState *swi = opaque;
412 
413     if (addr < (swi->num_harts << 2)) {
414         size_t hartid = swi->hartid_base + (addr >> 2);
415         CPUState *cpu = cpu_by_arch_id(hartid);
416         CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;
417         if (!env) {
418             qemu_log_mask(LOG_GUEST_ERROR,
419                           "aclint-swi: invalid hartid: %zu", hartid);
420         } else if ((addr & 0x3) == 0) {
421             return (swi->sswi) ? 0 : ((env->mip & MIP_MSIP) > 0);
422         }
423     }
424 
425     qemu_log_mask(LOG_UNIMP,
426                   "aclint-swi: invalid read: %08x", (uint32_t)addr);
427     return 0;
428 }
429 
430 /* CPU write [M|S]SWI register */
riscv_aclint_swi_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)431 static void riscv_aclint_swi_write(void *opaque, hwaddr addr, uint64_t value,
432         unsigned size)
433 {
434     RISCVAclintSwiState *swi = opaque;
435 
436     if (addr < (swi->num_harts << 2)) {
437         size_t hartid = swi->hartid_base + (addr >> 2);
438         CPUState *cpu = cpu_by_arch_id(hartid);
439         CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;
440         if (!env) {
441             qemu_log_mask(LOG_GUEST_ERROR,
442                           "aclint-swi: invalid hartid: %zu", hartid);
443         } else if ((addr & 0x3) == 0) {
444             if (value & 0x1) {
445                 qemu_irq_raise(swi->soft_irqs[hartid - swi->hartid_base]);
446             } else {
447                 if (!swi->sswi) {
448                     qemu_irq_lower(swi->soft_irqs[hartid - swi->hartid_base]);
449                 }
450             }
451             return;
452         }
453     }
454 
455     qemu_log_mask(LOG_UNIMP,
456                   "aclint-swi: invalid write: %08x", (uint32_t)addr);
457 }
458 
459 static const MemoryRegionOps riscv_aclint_swi_ops = {
460     .read = riscv_aclint_swi_read,
461     .write = riscv_aclint_swi_write,
462     .endianness = DEVICE_LITTLE_ENDIAN,
463     .valid = {
464         .min_access_size = 4,
465         .max_access_size = 4
466     }
467 };
468 
469 static const Property riscv_aclint_swi_properties[] = {
470     DEFINE_PROP_UINT32("hartid-base", RISCVAclintSwiState, hartid_base, 0),
471     DEFINE_PROP_UINT32("num-harts", RISCVAclintSwiState, num_harts, 1),
472     DEFINE_PROP_UINT32("sswi", RISCVAclintSwiState, sswi, false),
473 };
474 
riscv_aclint_swi_realize(DeviceState * dev,Error ** errp)475 static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp)
476 {
477     RISCVAclintSwiState *swi = RISCV_ACLINT_SWI(dev);
478     int i;
479 
480     memory_region_init_io(&swi->mmio, OBJECT(dev), &riscv_aclint_swi_ops, swi,
481                           TYPE_RISCV_ACLINT_SWI, RISCV_ACLINT_SWI_SIZE);
482     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &swi->mmio);
483 
484     swi->soft_irqs = g_new(qemu_irq, swi->num_harts);
485     qdev_init_gpio_out(dev, swi->soft_irqs, swi->num_harts);
486 
487     /* Claim software interrupt bits */
488     for (i = 0; i < swi->num_harts; i++) {
489         RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(swi->hartid_base + i));
490         /* We don't claim mip.SSIP because it is writable by software */
491         if (riscv_cpu_claim_interrupts(cpu, swi->sswi ? 0 : MIP_MSIP) < 0) {
492             error_report("MSIP already claimed");
493             exit(1);
494         }
495     }
496 }
497 
riscv_aclint_swi_reset_enter(Object * obj,ResetType type)498 static void riscv_aclint_swi_reset_enter(Object *obj, ResetType type)
499 {
500     /*
501      * According to RISC-V ACLINT spec:
502      *   - On MSWI device reset, each MSIP register is cleared to zero.
503      *
504      * p.s. SSWI device reset does nothing since SETSIP register always reads 0.
505      */
506     RISCVAclintSwiState *swi = RISCV_ACLINT_SWI(obj);
507     int i;
508 
509     if (!swi->sswi) {
510         for (i = 0; i < swi->num_harts; i++) {
511             /* Clear MSIP registers by lowering software interrupts. */
512             qemu_irq_lower(swi->soft_irqs[i]);
513         }
514     }
515 }
516 
riscv_aclint_swi_class_init(ObjectClass * klass,const void * data)517 static void riscv_aclint_swi_class_init(ObjectClass *klass, const void *data)
518 {
519     DeviceClass *dc = DEVICE_CLASS(klass);
520     dc->realize = riscv_aclint_swi_realize;
521     device_class_set_props(dc, riscv_aclint_swi_properties);
522     ResettableClass *rc = RESETTABLE_CLASS(klass);
523     rc->phases.enter = riscv_aclint_swi_reset_enter;
524 }
525 
526 static const TypeInfo riscv_aclint_swi_info = {
527     .name          = TYPE_RISCV_ACLINT_SWI,
528     .parent        = TYPE_SYS_BUS_DEVICE,
529     .instance_size = sizeof(RISCVAclintSwiState),
530     .class_init    = riscv_aclint_swi_class_init,
531 };
532 
533 /*
534  * Create ACLINT [M|S]SWI device.
535  */
riscv_aclint_swi_create(hwaddr addr,uint32_t hartid_base,uint32_t num_harts,bool sswi)536 DeviceState *riscv_aclint_swi_create(hwaddr addr, uint32_t hartid_base,
537     uint32_t num_harts, bool sswi)
538 {
539     int i;
540     DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_SWI);
541 
542     assert(num_harts <= RISCV_ACLINT_MAX_HARTS);
543     assert(!(addr & 0x3));
544 
545     qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
546     qdev_prop_set_uint32(dev, "num-harts", num_harts);
547     qdev_prop_set_uint32(dev, "sswi", sswi ? true : false);
548     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
549     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
550 
551     for (i = 0; i < num_harts; i++) {
552         CPUState *cpu = cpu_by_arch_id(hartid_base + i);
553         RISCVCPU *rvcpu = RISCV_CPU(cpu);
554 
555         qdev_connect_gpio_out(dev, i,
556                               qdev_get_gpio_in(DEVICE(rvcpu),
557                                   (sswi) ? IRQ_S_SOFT : IRQ_M_SOFT));
558     }
559 
560     return dev;
561 }
562 
riscv_aclint_register_types(void)563 static void riscv_aclint_register_types(void)
564 {
565     type_register_static(&riscv_aclint_mtimer_info);
566     type_register_static(&riscv_aclint_swi_info);
567 }
568 
569 type_init(riscv_aclint_register_types)
570